【题目描述】
XX在玩两个串的游戏。首先,他拿出了两个字符串 S 和 T,XX想知道 T
在 S 中出现了几次,分别在哪些位置出现。注意 T 中可能有“?”字符,这个字
符可以匹配任何字符。
【输入格式】
两行两个字符串,分别代表 S 和 T
【输出格式】
第一行一个正整数 k,表示 T 在 S 中出现了几次。
接下来 k 行正整数,
分别代表 T 每次在 S 中出现的开始位置。按照从小到大
的顺序输出,S 下标从 0 开始。
【样例输入】
ababcadaca
a?a
【样例输出】
3
0
5
7
【提示】
对于 10%的数据, S 和 T 的长度不超过 100
对于另外 20%的数据,T 中无“?”
对于 100%的数据,S 长度不超过 10^5,T 长度不会超过 S。S 中只包含小写
字母,T 中只包含小写字母和“?”
【来源】
经典题目
我猜是FFT 。。QAQ
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 300010
using namespace std;
struct cpx{
double r, i;
cpx(double a = 0, double b = 0):r(a), i(b){}
cpx operator+(const cpx& o)const{return cpx(r+o.r, i+o.i);}
cpx operator-(const cpx& o)const{return cpx(r-o.r, i-o.i);}
cpx operator*(const cpx& o)const{return cpx(r*o.r-i*o.i, r*o.i+i*o.r);}
cpx operator/(const double& k)const{return cpx(r/k, i/k);}
}P[maxn], A[maxn], B[maxn], C[maxn], D[maxn];
int r[maxn], l;
int rev(int S){
int ret = 0;
for(int i = 0; i < l; i ++){
ret = ret << 1 | (S & 1);
S >>= 1;
}return ret;
}
const double pi = acos(-1.0);
void FFT(cpx A[], int n, int t){
for(int i = 0; i < n; i ++) P[r[i]] = A[i];
for(int i = 0; i < n; i ++) A[i] = P[i];
for(int k = 2; k <= n; k <<= 1){
cpx wn = cpx(cos(2*pi/k), t*sin(2*pi/k));
for(int i = 0; i < n; i += k){
cpx w = cpx(1, 0);
for(int j = 0; j < k>>1; j ++){
cpx T = w * A[i+j+(k>>1)];
A[i+j+(k>>1)] = A[i+j] - T;
A[i+j] = A[i+j] + T;
w = w * wn;
}
}
}
if(t == -1)
for(int i = 0; i < n; i ++)
A[i] = A[i] / n;
}
char s[maxn];
int a[maxn], b[maxn], amt, ans[maxn];
const double eps = 1e-5;
int Filter(double x){return x < eps && x > -eps;}
long long sum;
double Q[maxn];
int main(){
freopen("guess.in", "r", stdin);
freopen("guess.out", "w", stdout);
scanf("%s", s);
int n1 = strlen(s);
for(int i = 0; i < n1; i ++)
a[i] = s[i] - 'a' + 1;
scanf("%s", s);
int n2 = strlen(s);
for(int i = 0; i < n2; i ++){
if(s[i] == '?') b[n2-i-1] = 0;
else b[n2-i-1] = s[i] - 'a' + 1;
}
for(int i = 0; i < n2; i ++)
sum += (long long)b[i] * b[i] * b[i];
int m1 = n1 + n2, n = 1; l = 0;
for(; n <= m1; n <<= 1, l ++);
for(int i = 1; i < n; i ++)r[i] = rev(i);
for(int i = 0; i < n1; i ++)A[i].r = (double)a[i] * a[i];
for(int i = 0; i < n2; i ++)B[i].r = b[i];
FFT(A, n, 1), FFT(B, n, 1);
for(int i = 0; i < n; i ++) C[i] = A[i] * B[i];
FFT(C, n, -1);
memset(A, 0, sizeof A);
memset(B, 0, sizeof B);
for(int i = 0; i < n1; i ++)A[i].r = a[i];
for(int i = 0; i < n2; i ++)B[i].r = (double)b[i] * b[i];
FFT(A, n, 1), FFT(B, n, 1);
for(int i = 0; i < n; i ++) D[i] = A[i] * B[i];
FFT(D, n, -1);
//for(int i = 0; i < n; i ++)printf("%.3lf ", C[i].r);puts("");
for(int i = 0; i < n; i ++)
Q[i] = C[i].r - 2 * D[i].r + sum;
for(int i = 0; i+n2-1 < n1; i ++)
if(Filter(Q[i+n2-1]))
ans[++ amt] = i;
printf("%d\n", amt);
for(int i = 1; i <= amt; i ++)
printf("%d\n", ans[i]);
return 0;
}
/*
Input
ababcadaca
a?a
Output
3
0
5
7
*/