1. 程式人生 > >BZOJ5217:[Lydsy2017省隊十連測]航海艦隊——題解

BZOJ5217:[Lydsy2017省隊十連測]航海艦隊——題解

可能 second complex rdquo sin pop 上下 ron 每天

https://www.lydsy.com/JudgeOnline/problem.php?id=5217

Byteasar 組建了一支艦隊!他們現在正在海洋上航行著。海洋可以抽象成一張n×m 的網格圖,其中有些位置是“.”,表示這一格是海水,可以通過;有些位置是“#”,表示這一格是礁石,不可以通過;有些位置是“o”,表示這一格目前有一艘艦,且艦離開這一格之後,這一格將變為“.”。這些“o” 表示Byteasar 的艦隊,他們每天可以往上下左右中的一個方向移動一格,但不能有任何一艘艦駛出地圖。特別地,Byteasar 對陣形有所研究,所以他不希望在航行的過程中改變陣形,即任何時刻任何兩艘艦的相對位置都不能發生變化。Byteasar 的艦隊可以航行無限長的時間,每當一艘艦經過某個格子的時候,這個格子海底的礦藏都將被Byteasar 獲得。請寫一個程序,幫助Byteasar 計算他最多可以獲得多少個格子海底的礦藏?

很妙……如果沒有做過類似的題可能打死也不知道是道FFT題。

首先將最小的包含所有艦隊的矩形拿出來,那麽先不考慮能否到達,我們只需要將這個小矩形和大矩形匹配,就能知道我們艦隊能夠放在哪裏。

於是想到暴力匹配,但是顯然是過不了的。

想到BZOJ4259:殘缺的字符串這道題,但是那是一維匹配,而我們要二維匹配。

所以一個想法就是降維,簡單點說,就是第一行字符+第二行字符+……

設大矩形為a[],小矩形(需要將大小填充等於大矩形)為b[]。

對於一個合法的匹配位置的左上角下標為p,則有對於所有的位置,都不能存在a[p+i]有礁石,b[i]有艦隊這種情況。

於是令a中礁石=1,b中艦隊=1,則就是f[i]=sigma(a[i+j]*b[j])=0,將a矩陣倒存,就有f[i]=sigma(a[n*m-i-j]*b[j])是一個卷積形式,於是FFT。

接下來考慮,對於所有的左上角,我們並不是都能到達的,所以從小矩陣最開始的左上角搜索找到所有合法的左上角。

最後就是一個點其下標為p,它能到達當其存在一個左上角p-i合法,且b[i]=1,於是令所有合法左上角=1,則f[i]=sigma(a[i-j]*b[j])>0,直接就是一個卷積,FFT求一遍就行了。

#include<map>
#include<cmath>
#include
<stack> #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef double dl; typedef pair<int,int>pii; #define fi first #define se second const dl pi=acos(-1.0); const dl eps=0.5; const int M=705; const int N=M*M*4; struct complex{ dl x,y; complex(dl xx=0,dl yy=0){ x=xx;y=yy; } complex operator +(const complex &b)const{ return complex(x+b.x,y+b.y); } complex operator -(const complex &b)const{ return complex(x-b.x,y-b.y); } complex operator *(const complex &b)const{ return complex(x*b.x-y*b.y,x*b.y+y*b.x); } }; void FFT(complex a[],int n,int on){ for(int i=1,j=n>>1;i<n-1;i++){ if(i<j)swap(a[i],a[j]); int k=n>>1; while(j>=k){j-=k;k>>=1;} if(j<k)j+=k; } for(int i=2;i<=n;i<<=1){ complex res(cos(-2*on*pi/i),sin(-2*on*pi/i)); for(int j=0;j<n;j+=i){ complex w(1,0); for(int k=j;k<j+i/2;k++){ complex u=a[k],t=w*a[k+i/2]; a[k]=u+t;a[k+i/2]=u-t; w=w*res; } } } if(on==-1) for(int i=0;i<n;i++)a[i].x/=n; } bool vis[M][M]; int n,m; int dx[4]={0,1,0,-1}; int dy[4]={1,0,-1,0}; char mp[M][M]; complex a[N],b[N]; queue<pii>q; void bfs(int sx,int sy){ q.push(pii(sx,sy)); vis[sx][sy]=0; while(!q.empty()){ int x=q.front().fi,y=q.front().se;q.pop(); a[(x-1)*m+y-1]=complex(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(pii(nx,ny)); } } } } int main(){ int x1=M,y1=M,x2=0,y2=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%s",mp[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(mp[i][j]==o)x1=min(x1,i),y1=min(y1,j),x2=max(x2,i),y2=max(y2,j); else if(mp[i][j]==#)a[n*m-(i-1)*m-j]=complex(1,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(mp[i][j]==o)b[(i-x1)*m+j-y1]=complex(1,0); int len=1; while(len<n*m)len<<=1; FFT(a,len,1);FFT(b,len,1); for(int i=0;i<len;i++)a[i]=a[i]*b[i]; FFT(a,len,-1); for(int i=1;i<=n-(x2-x1);i++) for(int j=1;j<=m-(y2-y1);j++) if(a[n*m-(i-1)*m-j].x<eps)vis[i][j]=1; for(int i=0;i<len;i++)a[i]=complex(0,0); bfs(x1,y1); FFT(a,len,1); for(int i=0;i<len;i++)a[i]=a[i]*b[i]; FFT(a,len,-1); int ans=0; for(int i=0;i<n*m;i++)if(a[i].x>eps)ans++; printf("%d\n",ans); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ5217:[Lydsy2017省隊十連測]航海艦隊——題解