题目传送门:http://www.nocow.cn/index.php/Translate:USACO/range
这道题的话如果不是之前做过类似的题目,我想我是做不出来的,大概就是先预处理s[i][j],表示前i行前j列有多少个1,然后O(1)时间判断这个正方形是否有1。
s[i][j]显然等于是s[i-1][j]+s[i][j-1]-s[i-1][j-1]+f[i][j](两个多边形重复的部分为s[i-1][j-1])
而判断第i行到第l行,第j列到第k列这个多边形内有没有(j-k+1)*(l-i+1)个1,显然只需判断s[i][j]-s[i-1][k]-s[l][j-1]+s[i-1][j-1]是否等于(j-k+1)*(l-i+1)就行了。(两个多边形的重复部分为s[i-1][j-1])
会有一点乱,但只要想一想图就好了,而且这道题是正方形,只要枚举边的长度就好了.
/* ID:abc31261 LANG:C++ TASK:range */ #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=260; int n,f[maxn][maxn],s[maxn][maxn],num[maxn]; int main() { int i,j,l; freopen("range.in","r",stdin); freopen("range.out","w",stdout); scanf("%d",&n); for (i=1;i<=n;i++) for (j=1;j<=n;j++)scanf("%01d",&f[i][j]); memset(s,0,sizeof(s)); memset(num,0,sizeof(num)); for (i=1;i<=n;i++) for (j=1;j<=n;j++)s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+f[i][j]; for (i=1;i<=n;i++) for (j=1;j<=n;j++) for (l=2;l<=min(n-i+1,n-j+1);l++) { int x=i+l-1,y=j+l-1; if (s[x][y]-s[x][j-1]-s[i-1][y]+s[i-1][j-1]==l*l)num[l]++; } for (i=1;i<=n;i++) if (num[i]!=0)printf("%d %d ",i,num[i]); return 0; }