题意:
有一个n*n(n<=1000)的01矩阵
Q次询问(1000) 每次询问有几个大于等于k的全为一的子矩形
从右下角往右上角预处理
每个点有一个r x v
r代表右边有多少连续1
x代表下面有多少连续1
v代表以这个为左上角的矩阵最大是多少
所以v[i][j]= min(r[i][j+1], x[i+1][j],v[i+1][j+1]) +1
r[i][j]=r[i][j+1]+1;
x[i][j]=x[i+1][j]+1;
然后ans[v[i][j]]++
预处理后缀和 O 1 输出
#include<cstdio> #include<cstring> #include<string> #include<iostream> #include<algorithm> #include<map> using namespace std; const int N=50005; int n,k,m; int s[1005]; int v[1005][1005],r[1005][1005],x[1005][1005],a[1005][1005]; char c[1005]; int main() { int i,j; int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(s,0,sizeof(s)); memset(r,0,sizeof(r)); memset(x,0,sizeof(x)); for(i=1; i<=n; i++) { scanf("%s",c); for(j=0;j<n;j++) a[i][j+1]=c[j]-‘0‘; } x[n+1][n]=0; r[n][n+1]=0; v[n+1][n+1]=0; for(i=n; i>=1; i--) { for(j=n; j>=1; j--) { if(a[i][j]) { v[i][j]=min(min(v[i+1][j+1],r[i][j+1]),x[i+1][j]); r[i][j]=r[i][j+1]+1; x[i][j]=x[i+1][j]+1; v[i][j]++; } else v[i][j]=r[i][j]=x[i][j]=0; s[v[i][j]]++; } } for(i=n-1; i>=1; i--) { s[i]+=s[i+1]; } while(m--) { scanf("%d",&k); cout<<s[k]<<endl; } } return 0; }
时间: 2024-08-24 20:06:41