BZOJ4503 两个串
没有传送门 因为是权限题 =.=
利用卷积来做字符串匹配问题= =+
如果我们现在有两个串 单纯要匹配它们我们可以怎么做呢
?
很明显是不可以的
因为可能出现这种情况
aabb
bbaa
两个部分抵消掉了=.=
我们如何处理这样的问题呢?平方!
这样子就好多了qwq
然后我们来处理通配符 通配符设为0然后乘上去就可以啦qwq
是不是非常优秀 = =+
然后我们回归原题
我们要处理所有的位置
那么就是
然后我们把它展开
我们发现了一些东西是不是可以卷积
没错 我们把b倒过来就可以进行卷积啦 = =+
就变成了
b[j]的三次是常数可以直接提出来
然后这个卷积 形式非常优美 分别做两次就可以了
注意这里的平方操作都只是系数自己 并不是多项式自乘哦
最后统计答案的时候对于s[i]=0那么就是答案咯
吐槽一句:样例真sb
附代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define inf 20021225
#define ll long long
#define db double
#define mxn 400010
#define eps 1e-8
using namespace std;
const db pi = acos(-1.0);
struct cpx
{
db x,y;
cpx(){}
cpx(db _x,db _y){x=_x,y=_y;}
};
cpx operator +(cpx a,cpx b){return cpx(a.x+b.x,a.y+b.y);}
cpx operator -(cpx a,cpx b){return cpx(a.x-b.x,a.y-b.y);}
cpx operator *(cpx a,cpx b){return cpx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
int rev[mxn];
int init(int n)
{
int lim=1,l=0;
while(lim<n) lim<<=1,l++;
for(int i=1;i<lim;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
return lim;
}
void fft(cpx *a,int n,int f)
{
for(int i=1;i<n;i++) if(rev[i]>i)
swap(a[rev[i]],a[i]);
for(int k=2,mid=1;k<=n;k<<=1,mid<<=1)
{
cpx Wn = cpx(cos(pi/mid),f*sin(pi/mid));
for(int i=0;i<n;i+=k)
{
cpx w = cpx(1.0,0.0);
for(int j=0;j<mid;j++,w=w*Wn)
{
cpx x=a[i+j],y=w*a[i+mid+j];
a[i+j] = x+y; a[i+mid+j] = x-y;
}
}
}
if(f==-1) for(int i=0;i<n;i++) a[i].x/=n;
}
char s[mxn],t[mxn]; int ls,lt,ans;
cpx f[mxn],g[mxn],h[mxn],p[mxn]; vector<int> vec;
int id(char ch){return ch=='?'?0:ch-'a'+1;}
int main()
{
//freopen("1.in","r",stdin);
scanf("%s%s",s,t); ls=strlen(s); lt=strlen(t); db ful=0.0;
for(int i=0;i<ls;i++) f[i].x=(db)id(s[i]),h[i].x=f[i].x*f[i].x;
for(int i=0;i<lt;i++) g[i].x=(db)id(t[lt-i-1]),ful = ful + g[i].x*g[i].x*g[i].x,p[i].x=g[i].x*g[i].x;
//for(int i=0;i<ls;i++) printf("%lf ",f[i].x);
int lim=init(ls+lt);
fft(f,lim,1); fft(g,lim,1); fft(h,lim,1); fft(p,lim,1);
for(int i=0;i<lim;i++) f[i]=cpx(2.0,0.0)*p[i]*f[i];
for(int i=0;i<lim;i++) h[i]=g[i]*h[i];
for(int i=0;i<lim;i++) h[i]=h[i]-f[i];
fft(h,lim,-1);
//printf("%lf\n",ful);
//for(int i=0;i<lim;i++) printf("%lf ",h[i].x);
for(int i=0;i<ls-lt+1;i++)
if(abs(h[i+lt-1].x+ful)<0.5) ans++,vec.push_back(i);
printf("%d\n",ans);
for(vector<int>::iterator it=vec.begin();it!=vec.end();it++)
printf("%d\n",*it);
return 0;
}
/**
bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
a?aba?abba
*/