题意:
边长为n的正方形棋盘内有一些坏的点 求出边长为k(n>=k>=2)的内部不含坏点的正方形有几个
思路:
本以为用二维树状数组可以搞定 可是准确算一下复杂度为O( n^3 * log2(n)^2 ) 还是TLE了
正确思路应该是dp 求出每个点左边和上面距离坏点的距离 O( n^2 )
再枚举每个点当小正方形的右下角的点 然后判断是否能构成边长为k的正方形 O( n^3 )
详细看代码
二维树状数组代码:(不能AC只是个思路)
/*
ID: housera1
PROG: range
LANG: C++
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define M 255
int n;
int x[M][M];
int lowbit(int i)
{
return i&(-i);
}
void add(int fx,int fy)
{
int i,j;
for(i=fx;i<=n;i+=lowbit(i))
{
for(j=fy;j<=n;j+=lowbit(j)) x[i][j]++;
}
}
int sum(int fx,int fy)
{
int i,j,res=0;
for(i=fx;i;i-=lowbit(i))
{
for(j=fy;j;j-=lowbit(j)) res+=x[i][j];
}
return res;
}
int main(){
int Debug=0;
if(!Debug){
freopen("range.in","r",stdin);
freopen("range.out","w",stdout);
}
char input[M];
int i,j,k=2,flag=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",input+1);
for(j=1;j<=n;j++)
{
if(input[j]=='1')
{
add(i,j);
flag++;
}
}
}
while(flag)
{
flag=0;
for(i=k;i<=n;i++)
{
for(j=k;j<=n;j++)
{
if(sum(i,j)-sum(i-k,j)-sum(i,j-k)+sum(i-k,j-k)==k*k) flag++;
}
}
if(flag)
{
printf("%d %d\n",k,flag);
k++;
}
}
return 0;
}
DP代码:(AC代码)
/*
ID: housera1
PROG: range
LANG: C++
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define M 255
int n;
int ans[M],yes[M][M],left[M][M],up[M][M];
int main(){
int Debug=0;
if(!Debug){
freopen("range.in","r",stdin);
freopen("range.out","w",stdout);
}
char input[M];
int i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",input+1);
for(j=1;j<=n;j++)
{
if(input[j]=='1') yes[i][j]=1;
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(yes[i][j])
{
left[i][j]=left[i][j-1]+1;
up[i][j]=up[i-1][j]+1;
}
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(!yes[i][j]||!yes[i-1][j-1]) continue;
for(k=2;k<=n;k++)
{
if(left[i][j]>=k&&up[i][j]>=k&&yes[i-1][j-1]>=k-1)
{
ans[k]++;
yes[i][j]++;
}
else break;
}
}
}
for(i=2;i<=n;i++)
{
if(ans[i]) printf("%d %d\n",i,ans[i]);
}
return 0;
}