Description
Byteasar 组建了一支舰队!他们现在正在海洋上航行着。
海洋可以抽象成一张n×m 的网格图,其中有些位置是“.”,表示这一格是海水,可以通过;有些位置是“#”,表示这一格是礁石,不可以通过;有些位置是“o”,表示这一格目前有一艘舰,且舰离开这一格之后,这一格将变为“.”。
这些“o” 表示Byteasar 的舰队,他们每天可以往上下左右中的一个方向移动一格,但不能有任何一艘舰驶出地图。特别地,Byteasar 对阵形有所研究,所以他不希望在航行的过程中改变阵形,即任何时刻任何两艘舰的相对位置都不能发生变化。
Byteasar 的舰队可以航行无限长的时间,每当一艘舰经过某个格子的时候,这个格子海底的矿藏都将被Byteasar 获得。请写一个程序,帮助Byteasar 计算他最多可以获得多少个格子海底的矿藏?
Input
第一行包含两个正整数n;m,分别表示地图的长和宽。
接下来n 行,每行有m 个字符,每个字符只能是“.”、“#”、“o” 中的一个。
输入数据保证至少有一个“o”。
Output
输出一行一个整数,即可以被经过的格子数的最大值。
Sample Input
4 5
…#
.o#.o
.o…o
…o…
Sample Output
12
Data Constraint
分析:
我们先找到一个最小的矩阵可以包含所有船。然后相当于在原图中对这个进行匹配。
可以考虑使用fft进行匹配,把原图中#设为1,船的矩阵中船设为1,然后匹配。可以得出每个节点成为矩阵左上角是否合法。
因为有的点合法但是到不了,所以我们要从初始点进行bfs求出可以到达的合法点。
一个节点可以到达满足左上角合法这个位置有船。可以用所有可以到达的合法点与船继续fft,大于0的点都可以到达。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
const int N=2e6+7;
const int maxn=707;
const double pi=acos(-1);
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
using namespace std;
int n,m,len,ans;
int f[N],g[N],r[N];
bool vis[maxn][maxn];
char a[maxn][maxn];
struct node{
int x,y;
};
queue <node> h;
struct rec{
double x,y;
}x[N],y[N],z[N],w[N];
rec operator +(rec a,rec b)
{
return (rec){a.x+b.x,a.y+b.y};
}
rec operator -(rec a,rec b)
{
return (rec){a.x-b.x,a.y-b.y};
}
rec operator *(rec a,rec b)
{
return (rec){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
}
void fft(rec *a,int f)
{
for (int i=0;i<len;i++)
{
if (i<r[i]) swap(a[i],a[r[i]]);
}
w[0]=(rec){1,0};
for (int i=2;i<=len;i*=2)
{
rec wn=(rec){cos(2*pi/i),f*sin(2*pi/i)};
for (int j=i/2;j>=0;j-=2) w[j]=w[j/2];
for (int j=1;j<i/2;j+=2) w[j]=w[j-1]*wn;
for (int j=0;j<len;j+=i)
{
for (int k=0;k<i/2;k++)
{
rec u=a[j+k],v=a[j+k+i/2]*w[k];
a[j+k]=u+v;
a[j+k+i/2]=u-v;
}
}
}
}
void FFT(int *a,int *b,int *c,int n,int m)
{
len=1;
int k=0;
while (len<(n+m)) len*=2,k++;
for (int i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(k-1));
for (int i=0;i<len;i++)
{
int A,B;
if (i<n) A=a[i]; else A=0;
if (i<m) B=b[i]; else B=0;
x[i]=(rec){A,0};
y[i]=(rec){B,0};
}
fft(x,1),fft(y,1);
for (int i=0;i<len;i++) z[i]=x[i]*y[i];
fft(z,-1);
for (int i=0;i<len;i++) c[i]=trunc(z[i].x/len+0.5);
}
int get(int x,int y)
{
return (x-1)*m+y-1;
}
int main()
{
freopen("sailing.in","r",stdin);
freopen("sailing.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%s",a[i]+1);
int lc,rc,ls,rs,p,q;
lc=ls=m;
rc=rs=0;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
if (a[i][j]=='o')
{
lc=min(lc,i);
ls=min(ls,j);
rc=max(rc,i);
rs=max(rs,j);
}
}
}
p=rc-lc+1,q=rs-ls+1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
f[get(i,j)]=(a[i][j]=='#');
if (a[i][j]=='o') g[get(i-lc+1,j-ls+1)]=1;
}
}
reverse(f,f+n*m);
FFT(f,g,f,n*m,n*m);
reverse(f,f+n*m);
vis[lc][ls]=1;
h.push((node){lc,ls});
while (!h.empty())
{
node d=h.front();
h.pop();
int x=d.x,y=d.y;
for (int i=0;i<4;i++)
{
if ((x+dx[i]>0) && (y+dy[i]>0) && (x+dx[i]<=n-p+1) && (y+dy[i]<=m-q+1))
{
if ((!f[get(x+dx[i],y+dy[i])]) && (!vis[x+dx[i]][y+dy[i]]))
{
vis[x+dx[i]][y+dy[i]]=1;
h.push((node){x+dx[i],y+dy[i]});
}
}
}
}
memset(f,0,sizeof(f));
for (int i=1;i<=n-p+1;i++)
{
for (int j=1;j<=m-q+1;j++)
{
f[get(i,j)]=vis[i][j];
}
}
FFT(f,g,f,n*m,n*m);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
if (f[get(i,j)]) ans++;
}
}
printf("%d",ans);
}