【FFT-類字串匹配】LOJ6388 [THUPC2018]賽艇 / Citing
阿新 • • 發佈:2018-11-28
【題目】
原題地址
給定一個
的
矩陣,其中
不能走。給定一個人的行走路線,求所有可能的起點。
【解題思路】
我們考慮將走的路徑看作
,然後將走出的路徑補
成為一個
矩陣。現在的問題就轉化為在原矩陣中放一個矩陣,使得兩個矩陣的或為
,求方案數。
將矩陣展開為一維後,實際上就是對應位置上的或值為
。
由於只有
和
,那麼或運算和乘法運算是等價的。
於是將其中一個序列反轉,做
,這時候卷積中第
位就代表下標和為
的各項乘積,實際上就表示路徑矩陣在原矩陣中起始位置為
時,矩陣各項的乘積和。
於是現在看對應位置中有多少為為0即可。
【參考程式碼】
#include<bits/stdc++.h>
using namespace std;
typedef double db;
const db pi=acos(-1);
const int N=5e6+10,M=N<<1;
int n,m,K,mxx,mix,mxy,miy,nx,ny,lim,L,ans;
int rev[M];
char s[N];
struct cd
{
db r,i;
cd(){}
cd(db r,db i):r(r),i(i){}
cd operator + (const cd&x)const{return cd(r+x.r,i+x.i);}
cd operator - (const cd&x)const{return cd(r-x.r,i-x.i);}
cd operator * (const cd&x)const{return cd(r*x.r-i*x.i,r*x.i+i*x.r);}
}a[M],b[M];
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;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("LOJ6388.in","r",stdin);
freopen("LOJ6388.out","w",stdout);
#endif
scanf("%d%d%d",&n,&m,&K);
for(int i=0;i<n;++i)
{
scanf("%s",s);
for(int j=0;j<m;++j) a[i*m+j].r=s[j]=='1';
}
scanf("%s",s);
for(int i=0;i<K;++i)
{
if(s[i]=='w') --nx;
else if(s[i]=='s') ++nx;
else if(s[i]=='a') --ny;
else ++ny;
mxx=max(mxx,nx);mix=min(mix,nx);
mxy=max(mxy,ny);miy=min(miy,ny);
}
nx=ny=0;mxx-=mix;mxy-=miy;
b[-mix*m-miy].r=1;
for(int i=0;i<K;++i)
{
if(s[i]=='w') --nx;
else if(s[i]=='s') ++nx;
else if(s[i]=='a') --ny;
else ++ny;
b[(nx-mix)*m+(ny-miy)].r=1;
}
//for(int i=0;i<n;++i,puts("")) for(int j=0;j<m;++j) printf("%.0lf ",b[i*m+j].r);
int t=n*m-1;
for(L=0,lim=1;lim<=2*t;) lim<<=1,++L;
for(int i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
reverse(b,b+t+1);
/*for(int i=0;i<lim;++i) printf("%0.lf ",a[i].r); puts("");
fft(a,lim,1);
for(int i=0;i<lim;++i) printf("%0.lf ",a[i].r); puts("");
fft(a,lim,-1);
for(int i=0;i<lim;++i) printf("%0.lf ",a[i].r); puts("");*/
fft(a,lim,1);fft(b,lim,1);
for(int i=0;i<lim;++i) a[i]=a[i]*b[i];
fft(a,lim,-1);
for(int i=0;i<n-mxx;++i) for(int j=0;j<m-mxy;++j)
if(a[t+i*m+j].r<0.5) ++ans;
printf("%d",ans);
return 0;
}
【總結】
一道轉化模型的好題,有點類似
解決字串匹配問題。