J The Escape Plan of Groundhog 2020牛客暑期多校训练营(第九场)

https://ac.nowcoder.com/acm/contest/5674/J

枚举上边界和下边界,从左到右扫枚举当前的列为右边界,要求有多少个左边界满足左边界也是没有空位的,而且横着的两条边也不为空,而且这个区间的有桌子和没桌子的差值最多是1,那么就维护一个(有桌子-没桌子)数量为值的前缀和,然后把当前列为右边界能连接的到左边界前缀和差1的数量就行了,这个用个桶维护数量就行

#include
using namespace std;
 
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(int &x){
    char c=nc(),f=1;
    for(;(c<'0'||c>'9')&&c!=EOF;c=nc()) if(c=='-') f=-1;
    if(c==EOF) return EOF;
    for(x=0;c>='0'&&c<='9';c=nc()) x=x*10+c-'0';
    x*=f;
    return 1;
}
 
 
int A[510][510],sum[510][510],B[510],ll[510][510];
int cnt[1000000],M=5e5,inf=1e9;
 
 
int qsum(int a,int b,int c,int d){
    if(a>c||b>d) return 0;
    return sum[c][d]+sum[a-1][b-1]-sum[a-1][d]-sum[c][b-1];
 
}
int f(int a,int b,int c,int d){
    if(a>c||b>d) return 0;
    int z=(c-a+1)*(d-b+1),x=qsum(a,b,c,d),y=z-x;
    return x-y;
}
 
int main(){
    int i,n,m,j,k,x;
    //scanf("%d%d",&n,&m);
    rd(n);rd(m);
    for(i=1;i<=n;i++) for(j=1;j<=m;j++) rd(x),A[i][j]=x;//scanf("%d",&A[i][j]);
    for(i=1;i<=n;i++) for(j=1;j<=m;j++) sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+A[i][j];
 
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            ll[i][j]=ll[i][j-1];
            if(A[i][j]==0) ll[i][j]=j;
        }
    }
 
    int now,a,b;
    long long ans=0;
    for(i=1;i<=n;i++){
        for(j=i+1;j<=n;j++){
            for(k=1;k<=m;k++){
                if(qsum(i,k,j,k)==j-i+1) B[k]=f(i+1,1,j-1,k);
                else B[k]=inf;
            }
            now=0;
            for(k=1;k<=m;k++){
                 if(B[k]!=inf){
                     b=max(ll[i][k],ll[j][k])+1;
                     while(now

 

你可能感兴趣的:(J The Escape Plan of Groundhog 2020牛客暑期多校训练营(第九场))