兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。
给cjr的题解跪啦~我这种菜鸡根本想不到这题怎么做呀qwq
如果没有通配符 考虑两个串匹配的条件
对于每个ai有ai==bi 即ai-bi=0
可转化为 sigma (ai-bi)²=0
考虑通配符 如果有通配符 无论ai是否等于bi 都不影响结果
将通配符权值赋为0
有 sigma bi*(a(i+k)-bi)²=0时两个串匹配
拆开得:
sigma bi * a(i+k)² +sigma bi^3 -2*sigma bi² * a(i+k) ==0 此处^3为三次方
翻转b数组求a和b的卷积g 判断下g(len2)到g(len1)区间经过运算后内0的个数 // 翻转后i=len2-i 仔细思考就发现这段区间为答案显然。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const double Pi=acos(-1);
const int MAXN=4e5+5;
struct cp{
double x,y;
cp(double xx=0,double yy=0){x=xx,y=yy;}
}a[MAXN],b[MAXN],c[MAXN],d[MAXN];
cp operator +(cp a,cp b){
return cp(a.x+b.x,a.y+b.y);
}
cp operator -(cp a,cp b){
return cp(a.x-b.x,a.y-b.y);
}
cp operator *(cp a,cp b){
return cp(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y);
}
int l,r[MAXN],limit=1,n,m;
void FFT(cp *A,int ty){
for(int i=0;i<limit;i++)
if(i<r[i])swap(A[i],A[r[i]]);
for(int mid=1;mid<limit;mid<<=1){
cp Wn(cos(Pi/mid),ty*sin(Pi/mid));
int R=mid<<1;
for(int j=0;j<limit;j+=R){
cp W(1,0);
for(int k=0;k<mid;k++){
cp x=A[j+k],y=W*A[j+k+mid];
A[j+k]=x+y;
A[j+k+mid]=x-y;
W=W*Wn;
}
}
}
}
int len1,len2;
char s1[MAXN],s2[MAXN];
ll ans=0;
ll numa[MAXN],numb[MAXN],powa[MAXN],powb[MAXN],sigmab3=0;
void rework(){
for(int i=0;i<=len1;i++){
numa[i]=s1[i]-'a'+1;
powa[i]=numa[i]*numa[i];
a[i].x=numa[i];
c[i].x=powa[i];
}
for(int i=0;i<=len2;i++){
numb[len2-i]=s2[i]=='?'?0:s2[i]-'a'+1;
powb[len2-i]=numb[len2-i]*numb[len2-i];
sigmab3+=(powb[len2-i]*numb[len2-i]);
b[len2-i].x=numb[len2-i];
d[len2-i].x=powb[len2-i];
}
}
ll sta[MAXN],top=0;
int main(){
scanf("%s%s",s1,s2);
len1=strlen(s1)-1,len2=strlen(s2)-1;
rework();
while(limit<=len1+len2)limit<<=1,l++;
for(int i=0;i<limit;i++){
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}
FFT(a,1);FFT(b,1);FFT(c,1);FFT(d,1);
for(int i=0;i<=limit;i++)a[i]=a[i]*d[i],b[i]=b[i]*c[i];
FFT(a,-1);FFT(b,-1);
ll ans=0;
int pos=0;
for(int i=len2;i<=len1;i++){
ll t1=(ll)(a[i].x/limit+0.5);
ll t2=(ll)(b[i].x/limit+0.5);
if(t2+sigmab3-2*t1==0)sta[++top]=pos;
pos++;
}
printf("%lld\n",top);
for(int i=1;i<=top;i++){
printf("%lld\n",sta[i]);
}
return 0;
}
/*
aaa
aa
*/