牛客多校第九场J-The Escape Plan of Groundhog(桶)(前缀和)

Description

牛客多校第九场J-The Escape Plan of Groundhog(桶)(前缀和)_第1张图片

Solution

  • 首先发现 n ∈ [ 1 , 500 ] n \in[1,500] n[1,500]的数据不要看成1500料想复杂度 O ( N 3 ) O(N^3) O(N3)
  • 我们枚举上下边缘,再一起扫过去
  • 我们考虑四边都为1的条件
  • 上下可以轻松维护,对左右,我们记 d i j d_{ij} dij为第 j j j列从上到下的前缀和
  • d i j = j − i + 1 d_{ij}=j-i+1 dij=ji+1表示当前列都是1
  • 再看内部01差不超过1的条件
  • 我们把0变成-1
  • s k s_k sk为到 k k k列为止 i i i行和 j j j行中间的前缀和
  • 用一个桶维护每个 s k s_k sk出现次数
  • ∣ s k 1 − s k 2 ∣ ≤ 1 |s_{k1}-s_{k2}|\leq1 sk1sk21即可表示内部01差不超过1,统计进答案里
#include 
const int N=510;
int n,m,ans,a[N][N],d[N][N],s[N],c[N*N];//c是桶
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",a[i]+j),a[i][j]=!a[i][j]?-1:1,d[i][j]=d[i-1][j]+a[i][j];
	for(int i=1;i<=n;i++)
		for(int j=i+1,pre=1;j<=n;j++){//pre:之前清零过的位置
			pre=1;
			for(int k=1;k<=m;k++){
				if(a[i][k]==-1||a[j][k]==-1){
					for(int l=pre;l<=k;l++)if(d[j][l]-d[i-1][l]==j-i+1) --c[s[l]];
					pre=k+1;continue;
				}if(d[j][k]-d[i-1][k]==j-i+1) ans+=c[s[k-1]]+c[s[k-1]+1]+c[s[k-1]-1];
				s[k]=s[k-1]+d[j-1][k]-d[i][k];
				if(d[j][k]-d[i-1][k]==j-i+1) ++c[s[k]];
			}for(int k=pre;k<=m;k++)if(d[j][k]-d[i-1][k]==j-i+1) --c[s[k]];
		}
	printf("%d\n",ans);		
}

你可能感兴趣的:(2020牛客暑期多校训练营)