問題の意味
本当に私は考えることはできません\(FFT \)基本的な夜の理解と、タイトルの。
それは、一次元の場合はまず第一に、我々は、大きな長方形の試合中に小さな四角形の問題を解決する必要があるこの質問。
今では、私たちがセクションに従って、各ラインを分割ます2次元である\(1 \)ライン、\(2 \)ラインを...最初の\(\ n)が行順につなぎ合わせ、綴るA長さ\(N * M \)文字列は、それで問題を考えます。
私たちは、私たちはただの方法として、文字列に扱われるこの長方形、艦隊の長方形と呼ばれる、艦隊を含む最小の矩形を最初に見つけます。
今、私たちは、私たちが呼ぶ、文字列のグラフを2つの文字列をされてい\(S \) 、もう一つは、私たちが呼んで長方形の艦隊の文字列です(\ T)\。
我々は2つの文字列の二つの配列構築\(A、Bを\) 。
\(A \)このシーケンスである\(S \)構築物、式中:\(a_iを= [S_I = \#] \) 、すなわち、もし\(I \)この時点で障害、次いで\(a_iを= 1 \) 。
\(B \)このシーケンスである\(T \)構築物、請求\(B_i = T_I = O] \) 、すなわち、もし\(I \) 、次いで、船舶用フリート矩形のこの時点で\(B_i = 1 \) 。
私たちは、今の場所を検討し\(xと\) 、我々は決定する必要があり、\(X \)艦隊は艦隊がこの位置に移動することができるかどうか、である四角形の左上隅になりますかどうかを。
場合\(X \)条件が満たされる場合にのみ\((\ \ limits_ {I = 0} ^ {NM-X- 1} A_は、{X + I} B_i)が0 \ SUM =)を、存在しないことを示し\(I \)を満足\(A_ {I} = X + 1 \&\&B_i。1 = \) 、各ボートの即ち位置には障害を持つべきではありません。
我々は、(A \)\逆さまになる\(A「\) 、次いで、上記の式になる:\((\ SUM \ limits_ = {I + J-X} a'_ib_j NM)= 0 \ )、それは実際には(\和\ limits_ {I \ + J = X} a'_ib_jが\) 我々ができ、それを反転\(FFT \)迅速に得ます。
今、私たちはすべての取得のポイントを置くことができますが、いくつかのポイントが届かないことがあり、我々はピット\(BFSを\)これらの除外だけで罰金のポイントに到達しません。
我々は、シーケンスに艦隊でカバーできるポイント数、今我々が到達するために、すべての左上隅を知って、対応を尋ねた後、(A \)\(もし\ I(\)左に移動するには、この時点で正当なポイントです、次に\(= a_iを1 \。) )、次いで、位置\(X \) :場合にのみ上書きできる\((\ SUM \ limits_ {X = I + J} a_ib_j)> 0 \)以上で存在します左エンドポイント\(I \) 、および\(I + J \) 、この位置では、船、裸より多くの畳み込みを持っています。
コード:
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
const int maxn=710;
const int maxm=2000010;
const int inf=1e9;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const double Pi=acos(-1.0);
const double eps=0.5;
int n,m,x1=inf,yy1=inf,x2,y2,ans;
char a[maxn][maxn];
bool vis[maxn][maxn];
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
struct cplx{double x,y;}A[maxm],B[maxm];
cplx operator+(cplx a,cplx b){return (cplx){a.x+b.x,a.y+b.y};}
cplx operator-(cplx a,cplx b){return (cplx){a.x-b.x,a.y-b.y};}
cplx operator*(cplx a,cplx b){return (cplx){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
int lim=1,len;
int pos[maxm];
inline void FFT(cplx* a,int op)
{
for(int i=0;i<lim;i++)if(i<pos[i])swap(a[i],a[pos[i]]);
for(int l=1;l<lim;l<<=1)
{
cplx wn=(cplx){cos(Pi/l),op*sin(Pi/l)};
for(int i=0;i<lim;i+=l<<1)
{
cplx w=(cplx){1,0};
for(int j=0;j<l;j++,w=w*wn)
{
cplx x=a[i+j],y=w*a[i+l+j];
a[i+j]=x+y;a[i+l+j]=x-y;
}
}
}
if(op==1)return;
for(int i=0;i<lim;i++)a[i].x/=lim;
}
void bfs(int sx,int sy)
{
queue<pii>q;
q.push(mkp(sx,sy));
vis[sx][sy]=0;
while(!q.empty())
{
pii now=q.front();q.pop();
int x=now.fir,y=now.sec;
A[(x-1)*m+y-1].x=1;
for(int i=0;i<4;i++)
{
int mx=x+dx[i],my=y+dy[i];
if(vis[mx][my])vis[mx][my]=0,q.push(mkp(mx,my));
}
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='o')x1=min(x1,i),yy1=min(yy1,j),x2=max(x2,i),y2=max(y2,j);
else if(a[i][j]=='#')A[n*m-(i-1)*m-j]=(cplx){1,0};
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='o')B[(i-x1)*m+j-yy1]=(cplx){1,0};
while(lim<n*m)lim<<=1,len++;
for(int i=0;i<lim;i++)pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
FFT(A,1);FFT(B,1);
for(int i=0;i<lim;i++)A[i]=A[i]*B[i];
FFT(A,-1);
for(int i=1;i<=n-(x2-x1);i++)
for(int j=1;j<=m-(y2-yy1);j++)
if(A[n*m-(i-1)*m-j].x<eps)vis[i][j]=1;
for(int i=0;i<lim;i++)A[i]=(cplx){0,0};
bfs(x1,yy1);
FFT(A,1);
for(int i=0;i<lim;i++)A[i]=A[i]*B[i];
FFT(A,-1);
for(int i=0;i<n*m;i++)if(A[i].x>eps)ans++;
printf("%d",ans);
return 0;
}