【BZOJ】5217: [Lydsy2017省隊十連測]航海艦隊 -myyFFT
阿新 • • 發佈:2018-12-10
題解
為方便表示,首先設下標從開始,座標範圍。
可以把環境圖(只考慮海水和礁石)一行一行接起來轉換成一個長度為的串(若下標從開始,則表示位置上有礁石。
同樣把包圍艦隊的最小矩形摳出來,保留最上一行到右下角的位置的狀態轉換成串(設矩形上下邊界分別為,左右邊界分別為,則表示從到的所有點的狀態,串長,表示位置上有艦。
考慮到當且僅當中長度為的串(設右下角的點為)不存在的情況時,艦隊右下角可以處於(能否到達可以求出,這裡先求出能否處於的位置),那麼將串翻轉,變成就成了卷積形式,做一遍即可。
卷積過後,若某一點位置上為,則表示可以處於,從艦隊初始右下角的點開始,得到所有可以到達的點,轉換成串(表示艦隊可以處於位置)。
每個點第一次被到達才產生貢獻,所以會算重。考慮一個點,若存在,所以同樣轉成了卷積形式。再後統計係數大於的個數即可(實際上對應的是位數上的點是否被到達)。
用myyfft似乎要快一些
程式碼
#include<bits/stdc++.h>
#define RI register
using namespace std;
typedef double db;
const int N=2e6+10,M=702;
const int MX=M*M;
const db pi=acos(-1.0);
int ans,n,m,all,are,len,L,rv[N],t[MX];
int xx[2],yy[2],H,W,g[MX],vs[MX];
char s[M][M];
struct P{
int x,y;
P(){};
P(int x_,int y_){x=x_;y=y_;}
}temp;
queue<P>que;
struct cc{
db r,i;
cc(){r=i=0;};
cc(db r_,db i_){r=r_;i=i_;}
cc operator +(const cc&ky){return cc(r+ky.r,i+ky.i);}
cc operator -(const cc&ky){return cc(r-ky.r,i-ky.i);}
cc operator *(const cc&ky){return cc(r*ky.r-i*ky.i,r*ky.i+i*ky.r);}
cc operator /(const int&ky){return cc(r/(db)ky,i/(db)ky);}
inline cc conj(){return cc(r,-i);}
}a[N],b[N];
inline void FFT(cc *e,int ptr)
{
RI int i,j,k,t;cc bs,ori,ix,iy;
for(i=1;i<len;++i) if(i<rv[i]) swap(e[i],e[rv[i]]);
for(i=1;i<len;i<<=1){
ori=cc(cos(pi/i),ptr*sin(pi/i));
for(j=0;j<len;j+=(i<<1)){
bs=cc(1,0);
for(k=0;k<i;++k,bs=bs*ori){
ix=e[j+k];iy=e[i+j+k]*bs;
e[j+k]=ix+iy;e[i+j+k]=ix-iy;
}
}
}
if(ptr==1) return;
for(i=0;i<len;++i) e[i]=e[i]/len;
}
inline void init()
{
RI int i,j,pos=0;
scanf("%d%d",&n,&m);
all=n*m;
xx[0]=n+1;yy[0]=m+1;
for(i=0;i<n;++i){
scanf("%s",s[i]);
for(j=0;j<m;++j){
if(s[i][j]=='#') a[pos].r=1;
else if(s[i][j]=='o'){
xx[0]=min(i,xx[0]);
xx[1]=max(i,xx[1]);
yy[0]=min(j,yy[0]);
yy[1]=max(j,yy[1]);
}
pos++;
}
}
H=xx[1]-xx[0]+1;W=yy[1]-yy[0]+1;
pos=0;are=(H-1)*m+W;
for(i=xx[0];i<=xx[1];++i,pos+=m)
for(j=yy[0];j<=yy[1];++j)
if(s[i][j]=='o')
a[are-1-pos-j+yy[0]].i=1,
t[pos+j-yy[0]]=1;
}
inline void ins(P p)
{
int rc=p.x*m+p.y;
if(!g[rc] || vs[rc]) return;
vs[rc]=1;
if(p.x>0) que.push(P(p.x-1,p.y));
if(p.x<n-1) que.push(P(p.x+1,p.y));
if(p.y>0) que.push(P(p.x,p.y-1));
if(p.y<m-1) que.push(P(p.x,p.y+1));
}
inline void work()
{
RI int i,j;
for(len=1,L=0;len<all+are;len<<=1) L++;
for(i=1;i<len;++i) rv[i]=(rv[i>>1]>>1)|((i&1)<<(L-1));
FFT(a,1);
for(i=0;i<len;++i){
j=(len-i)&(len-1);
b[i]=(a[i]*a[i]-(a[j]*a[j]).conj())*cc(0,-0.25);
}
FFT(b,-1);
for(i=H-1;i<n