【题目】
BZOJ
一个
n
×
m
n\times m
n×m的网格图,其中".“表示海水,”#"表示障碍,"o"表示舰队,舰队可以四方向移动,要求舰队内部的相对位置不变,问舰队最多能经过多少个格子。
n
,
m
≤
700
n,m\leq 700
n,m≤700
【解题思路】
根据
THUPC
\text{THUPC}
THUPC的赛艇这题,不难想到可以用
FFT
\text{FFT}
FFT进行匹配。
那么二维转一维以后是个矩形匹配问题,将舰队的位置和障碍的位置设成
1
1
1然后反过来一个,结果为
0
0
0的位置就是舰队矩形可行的左上角(或者你自己搞的其他什么特征)。
最后再
DFS
\text{DFS}
DFS一遍可以得到答案。
【参考代码】
#include<bits/stdc++.h>
#define fi first
#define se second
#define mkp make_pair
#define id(x,y) (x*m+y)
using namespace std;
typedef pair<int,int> pii;
typedef double db;
const int N=705,M=N*N*4;
const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
const db pi=acos(-1),eps=0.5;
int n,m,xl,yl,xr,yr;
namespace Poly
{
int L,mm,rev[M];
struct cd
{
db r,i;
cd(db _r=0,db _i=0):r(_r),i(_i){}
cd operator +(const cd&rhs)const{return cd(r+rhs.r,i+rhs.i);}
cd operator -(const cd&rhs)const{return cd(r-rhs.r,i-rhs.i);}
cd operator *(const cd&rhs)const{return cd(r*rhs.r-i*rhs.i,r*rhs.i+i*rhs.r);}
}a[M],b[M];
void reget(int x)
{
for(L=0,mm=1;mm<=x;mm<<=1,++L);
for(int i=0;i<mm;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
}
void fft(cd *a,int n,int f)
{
for(int i=0;i<n;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=1;i<n;i<<=1)
{
cd wn=cd(cos(pi/i),f*sin(pi/i));
for(int j=0;j<n;j+=(i<<1))
{
cd w=cd(1,0);
for(int k=0;k<i;++k,w=w*wn)
{
cd x=a[j+k],y=w*a[i+j+k];
a[j+k]=x+y;a[i+j+k]=x-y;
}
}
}
if(!~f) for(int i=0;i<n;++i) a[i].r/=n;
}
}
using namespace Poly;
namespace DreamLolita
{
int ans,vis[N][N];
char mp[N][N];
queue<pii>q;
void bfs(int x,int y)
{
q.push(mkp(x,y));vis[x][y]=0;
while(!q.empty())
{
x=q.front().fi;y=q.front().se;q.pop();
a[(x-1)*m+y-1]=cd(1,0);
for(int i=0;i<4;++i)
{
int nx=x+dx[i],ny=y+dy[i];
if(vis[nx][ny]) vis[nx][ny]=0,q.push(mkp(nx,ny));
}
}
}
void solve()
{
scanf("%d%d",&n,&m);xl=yl=N;xr=yr=0;
for(int i=1;i<=n;++i)
{
scanf("%s",mp[i]+1);
for(int j=1;j<=m;++j)
{
if(mp[i][j]=='o') xl=min(xl,i),yl=min(yl,j),xr=max(xr,i),yr=max(yr,j);
else if(mp[i][j]=='#') a[n*m-(i-1)*m-j]=cd(1,0);
}
}
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
if(mp[i][j]=='o') b[(i-xl)*m+j-yl]=cd(1,0);
reget(n*m);
fft(a,mm,1);fft(b,mm,1);
for(int i=0;i<mm;++i) a[i]=a[i]*b[i];
fft(a,mm,-1);
for(int i=1;i<=n-(xr-xl);++i) for(int j=1;j<=m-(yr-yl);++j)
if(a[n*m-(i-1)*m-j].r<eps) vis[i][j]=1;
for(int i=0;i<mm;++i) a[i]=cd(0,0);
bfs(xl,yl);
fft(a,mm,1);
for(int i=0;i<mm;++i) a[i]=a[i]*b[i];
fft(a,mm,-1);
for(int i=0;i<n*m;++i) if(a[i].r>eps) ++ans;
printf("%d\n",ans);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ5217.in","r",stdin);
freopen("BZOJ5217.out","w",stdout);
#endif
DreamLolita::solve();
return 0;
}