LOJ6388:[THUPC2018]赛艇——题解
如果你做过BZOJ5217:[Lydsy2017省队十连测]航海舰队的话,那么恭喜你,这道题就是大水题。
如果你做过BZOJ4259:残缺的字符串的话,那么基本的字符串匹配FFT也是能想到的。
如果没做过的话,很抱歉,没有一定的套路的话这道题很难想(而对于我这样的蒟蒻来说就是没法想。)
将行走路线看做一个地图b,走过的路为1,没走的为0.
于是可以变成这张地图可以与原地图a匹配多少次(匹配成功在于两张图的1不能重叠。)
按照BZOJ5217的套路,将二维压成一维,就变成了对于一个下标为p的点,不满足a[p+i]=1且b[i]=1。
于是有f[i]=sigma(a[i+j]*b[j])=0,将a数组颠倒得f[i]=sigma(a[n*m-i-j]*b[j])=0是卷积,可以FFT运算。
最后统计f[i]=0的个数即可。
#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; const dl pi=acos(-1.0); const dl eps=0.5; const int M=1505; const int N=M*M*8; const int K=5e6+5; 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 tmp[M*2+10][M*2+10]; int n,m,k; char mp[M][M],s[K]; complex a[N],b[N]; int main(){ scanf("%d%d%d",&n,&m,&k); 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]=='1')a[n*m-(i-1)*m-j]=complex(1,0); scanf("%s",s); int x=n,y=m; int x1=n,y1=m,x2=n,y2=m; tmp[x][y]=1; for(int i=0;i<k;i++){ if(s[i]=='w')x--; if(s[i]=='a')y--; if(s[i]=='s')x++; if(s[i]=='d')y++; tmp[x][y]=1; x1=min(x1,x),y1=min(y1,y),x2=max(x2,x),y2=max(y2,y); } for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) if(tmp[i][j])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); int ans=0; 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)ans++; printf("%d\n",ans); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++