题目描述:
给一个文本串和一个模式串,模式串中有通配符$'?'$,
问匹配多少次,哪里可以匹配。
题解:
极为暴力,$FFT$单字符匹配$26$次,总计$26*3=78$次$FFT$。
其实有更好的方法我放在下一篇博客里
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const double Pi = acos(-1.0); const int N = 300050; struct cp { double x,y; cp(){} cp(double x,double y):x(x),y(y){} cp operator + (const cp&a)const{return cp(x+a.x,y+a.y);} cp operator - (const cp&a)const{return cp(x-a.x,y-a.y);} cp operator * (const cp&a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }; int to[4*N],lim=1,l; void fft(cp *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { cp w0(cos(Pi/i),k*sin(Pi/i)); for(int j=0;j<len;j+=(i<<1)) { cp w(1,0); for(int o=0;o<i;o++,w=w*w0) { cp w1=a[j+o],w2 = a[j+o+i]*w; a[j+o] = w1+w2; a[j+o+i] = w1-w2; } } } if(k==-1)for(int i=0;i<len;i++)a[i].x/=len; } char s1[N],s2[N]; int n,m,ans[N]; cp a[4*N],b[4*N],c[4*N]; bool vis[28]; void sol(int x) { for(int i=0;i<lim;i++)a[i]=b[i]=cp(0,0); for(int i=0;i<n;i++)if(s1[i]=='a'+x)a[i].x=1; for(int i=0;i<m;i++)if(s2[i]=='a'+x)b[m-i-1].x=1; fft(a,lim,1),fft(b,lim,1); for(int i=0;i<lim;i++)c[i]=a[i]*b[i]; fft(c,lim,-1); for(int i=0;i<lim;i++)ans[i]+=(int)(c[i].x+0.5); } int main() { // freopen("6.in","r",stdin); scanf("%s%s",s1,s2); n = strlen(s1),m = strlen(s2); for(int i=0;i<n;i++)vis[s1[i]-'a']=1; for(int i=0;i<m;i++)if(s2[i]!='?')vis[s2[i]-'a']=1; while(lim<2*(n+m))lim<<=1,l++; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1))); for(int i=0;i<26;i++)if(vis[i])sol(i); int cnt = 0,sum = 0; for(int i=0;i<m;i++)if(s2[i]!='?')cnt++; for(int i=m-1;i<n;i++)if(ans[i]==cnt)sum++; printf("%d ",sum); for(int i=m-1;i<n;i++)if(ans[i]==cnt)printf("%d ",i-m+1); return 0; }