Description
Input
Output
Sample Input
Sample Output
Data Constraint
Solution
因nm同阶所以以下把m当成n
subtask1,2
并不知道怎么做
subtask3,4
枚举四边界再暴力bfs找连通块,时间复杂度O(n^6)
subtask5,6
发现只要有大于一个黑色格子就不合法,所以枚举上下右边界,左边界范围可以算出来 时间复杂度 O(n^3)
subtask7,8
考虑欧拉公式n+r=m+2,由于不存在空腔所以r=四元环个数+1,因此有 n+四元环个数-m=1
把点,横边,竖边,四元环找出来前缀和,枚举上下右边界,左边界用桶直接求 时间复杂度 O(n^3)
这里注意:
前缀和统计答案的时候我们统计,当前(上下右边界前面所有的n+四元环个数-m)减去桶中前面某一个右端点结束的前缀和=1的个数
【也就是查询桶中当前(上下右边界前面所有的n+四元环个数-m)-1的个数。】
但是我们发现这样统计的并不是严格的某个矩形中的n+r-m的值,因为左端点与左端点前面那一列的四元环个数以及横边的个数没有减去
因此用桶存的时候 ,要存 值为【( 上下右边界前面所有的n+四元环个数-m的值)+(当前右边界与右边一列的四元环个数以及横边的个数)】的个数 。
subtask9,10
发现如果一个子矩形里面存在空腔,则将其四边界扩展后空腔仍存在
bfs/dfs找出所有空腔,总数上限为n^2 ,在固定了上下右边界后,每个空腔是对左边界的限制
把空腔所在的子矩形(x1,y1,x2,y2)找出来,在上边界<=x1-1时在(x2+1,y2+1)处打上y1-1的限制,之后枚 举下右边界时再处理出c[i]表示当前右边界为i的最大左边界,指针+桶单调维护左边界
时间复杂度O(n^3)
为什么倒数第二个数据点本地跑答案总是错的交上去就A了?T^T
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define F(i,a,b) for(register I i=a;i<=b;i++)
#define N 303
using namespace std;
I n,m,a[N][N],s[N][N],dt[N],t[N*N+300],e[N][N],E[N][N],c[N][N],bz[N][N],x1,x2,y1,y2,l,ans,tot;
struct node{I x1,y1,x2,y2;}v[N*N];
char ch;
I R(I &x){
x=0;I w=1;ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*=w;
}
void dg(I x,I y){
if(x<=0||y<=0||x>n||y>m||a[x][y]||bz[x][y]) return;
bz[x][y]=1;
x1=min(x1,x),x2=max(x2,x),y1=min(y1,y),y2=max(y2,y);
dg(x-1,y),dg(x+1,y),dg(x,y-1),dg(x,y+1);
}
I cmp(node a,node b){return a.x1>b.x1;}
I main(){
freopen("village.in","r",stdin);
freopen("village.out","w",stdout);
R(n),R(m);
F(i,1,n){
F(j,1,m){
ch=getchar();
while(ch!='0'&&ch!='1') ch=getchar();
a[i][j]=ch=='1';
s[i][j]=s[i-1][j]+a[i][j];
}
}
F(i,1,n){
F(j,1,m) if(!a[i][j]&&!bz[i][j]){
dg(x1=x2=i,y1=y2=j);
if(--x1&&--y1&&++x2<=n&&++y2<=m) v[++tot]=node{x1,y1,x2,y2};
}
}
sort(v+1,v+1+tot,cmp);
F(i,1,n){
F(j,1,m){
e[i][j]=e[i-1][j]+(a[i][j]&a[i-1][j]);
E[i][j]=E[i-1][j]+(a[i][j]&a[i][j-1]);
c[i][j]=c[i-1][j]+(a[i][j]&a[i-1][j]&a[i][j-1]&a[i-1][j-1]);
}
}
F(i,1,n){
F(j,i,n) F(k,1,m) bz[j][k]=0;
F(j,1,tot){
if(i<=v[j].x1) bz[v[j].x2][v[j].y2]=max(bz[v[j].x2][v[j].y2],v[j].y1);
else break;
}
F(j,i,n){
l=0;t[0]=1;//注意边界情况,l从0开始删,调了好久
F(k,1,m){
bz[j][k]=max(bz[j][k],bz[j-1][k]);
while(l<bz[j][k]) t[dt[l]+c[j][l+1]-c[i][l+1]-E[j][l+1]+E[i-1][l+1]]--,l++;
dt[k]=dt[k-1]+s[j][k]-s[i-1][k]+c[j][k]-c[i][k]-e[j][k]+e[i][k]-E[j][k]+E[i-1][k];
ans+=t[dt[k]-1];
t[dt[k]+c[j][k+1]-c[i][k+1]-E[j][k+1]+E[i-1][k+1]]++;
}
F(k,0,m) t[dt[k]+c[j][k+1]-c[i][k+1]-E[j][k+1]+E[i-1][k+1]]=0,dt[k]=0;
}
}
printf("%d\n",ans);
return 0;
}