Description
爱偷懒的小X这次玩起了一个幼稚的游戏。他拿出若干相同长度的火柴棍,在地上摆了起来。摆着摆着小X发现火柴不够,不能按原先的设想摆出一个N×N的正方形网格。只剩下最后一根火柴了,于是小X把这根火柴交给了LHX教主。小X只有一个要求,就是在现有的基础上能让这个不怎么好看的网格再多出至少一个正方形(你可以认为一个2×2完整网格有5个正方形)。
但是LHX教主为了显示他足够NB,他想把所有满足要求的位置都告诉小X。现在假如你就是LHX教主,你只需要输出有多少个位置放下一根火柴后可以让整个网格多出至少一个正方形。
题解
遇到正方形,显然想到枚举对角线。
我们可以先预处理出来每一个位置向上下左右的长度,
在同一条对角线上任意两点都可以构成一个正方形。
通过之前预处理出来的长度,我们可以知道一个点它向左和向下的边长,
然后在这个边长空一个位置,可以找到另一个边长。
那么夹在两个边长中如果有点就可以通过补这个位置得到新的正方形。
code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 2003
using namespace std;
bool bz[N][N][2];
char ch;
int n,ans,len,t,x,y;
bool p[N][N][2];
int up[N][N],down[N][N],le[N][N],ri[N][N],del[N],b[N],next[N],tot;
int tr[N];
int find(int x)
{
int s=0;
if(x<=0)return 0;
for(;x;x=x-(x&(-x)))
s+=tr[x];
return s;
}
void add(int x,int z)
{
if(x<=0)return;
for(;x<=n+1;x=x+(x&(-x)))
tr[x]+=z;
}
void work(int x,int y)
{
memset(tr,0,sizeof(tr));
memset(del,0,sizeof(del));
memset(next,0,sizeof(next));
memset(b,0,sizeof(b));
for(tot=1;x<=n+1 && y>0;x++,y--,tot++)
{
for(int k=b[x];k;k=next[k])add(del[k],-1);
if(up[x][y]<ri[x][y])
{
len=up[x][y];
t=min(ri[x][y],up[x-len-1][y]+len+1);
if(find(x-len-1)-find(x-t-1)>0)
{
if(p[x-len-1][y][1])ans++;
p[x-len-1][y][1]=0;
}
}
else
{
len=ri[x][y];
t=min(up[x][y],ri[x][y+len+1]+len+1);
if(find(x-len-1)-find(x-t-1)>0)
{
if(p[x][y+len][0])ans++;
p[x][y+len][0]=0;
}
}
add(x,1);
len=min(down[x][y],le[x][y])+1;
next[tot]=b[x+len];
del[tot]=x;
b[x+len]=tot;
//add(x+len,-1);
//for(int k=x;k<x+len;k++)add(k,1);
}
}
void work1(int x,int y)
{
memset(tr,0,sizeof(tr));
memset(del,0,sizeof(del));
memset(next,0,sizeof(next));
memset(b,0,sizeof(b));
for(tot=1;x>0 && y<=n+1;x--,y++,tot++)
{
for(int k=b[x];k;k=next[k])add(del[k],-1);
if(le[x][y]<down[x][y])
{
len=le[x][y];
t=min(down[x][y],le[x][y-len-1]+len+1);
if(find(x+t)-find(x+len)>0)
{
if(p[x][y-len-1][0])ans++;
p[x][y-len-1][0]=0;
}
}
else
{
len=down[x][y];
t=min(le[x][y],down[x+len+1][y]+len+1);
if(find(x+t)-find(x+len)>0)
{
if(p[x+len][y][1])ans++;
p[x+len][y][1]=0;
}
}
add(x,1);
len=min(up[x][y],ri[x][y]);
next[tot]=b[x-len-1];
del[tot]=x;
b[x-len-1]=tot;
//add(x+len,-1);
//for(int k=x;k<x+len;k++)add(k,1);
}
}
int main()
{
freopen("data10.in","r",stdin);
scanf("%d",&n);
memset(bz,0,sizeof(bz));
memset(p,1,sizeof(p));
ch=getchar();
for(int i=1;i<=n+1;i++)
{
ch=getchar();
while(ch!='_' && ch!='|' && ch!=' ')ch=getchar();
for(int j=1;j<=2*n+1;j++)
{
//printf("%c",ch);
if(ch=='_')bz[i][j/2+1][0]=1;
if(ch=='|')bz[i][j/2+1][1]=1;
ch=getchar();
}
//printf("\n");
}
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n+1;j++)
{
if(bz[i][j][0])le[i][j]=le[i][j-1]+1;
if(bz[i][j][1])up[i][j]=up[i-1][j]+1;
}
for(int i=n+1;i;i--)
for(int j=n+1;j;j--)
{
if(bz[i][j+1][0])ri[i][j]=ri[i][j+1]+1;
if(bz[i+1][j][1])down[i][j]=down[i+1][j]+1;
}
for(int i=1;i<=n+1;i++)
work(1,i),work1(n+1,i);
for(int i=1;i<=n+1;i++)
work(i,n+1),work1(i,1);
printf("%d",ans);
}