体会一下fft和字符串匹配的相似过程,然后就好了。。。
主要是卷积方式和字符串匹配很像:
a:1 2 3 4
b:1 2 3 4
c=a*b;
那么c的第三位是什么呢?
a:3 2 1
+ + +
b:1 2 3:
c:4+4+4=12;
所以是12;
第二位呢?
a:1 2
b:2 1
c:3+3=6;
所以是6;
体会一下这种卷积的交叉性你就会发现其实和字符串匹配很像
然后问题是:
a[i]=b[i]是否都成立,变一下形式a[i]-b[i]=0;
要判断一个东西是否为0目前我所知有:
1.a>=0且a<=0;
2.a*b=0且b!=0;
3.直接推出a=0;
如果我们重第一种请矿出发,可以想到用单纯性或者是最短路什么的,但是复杂度gg
如果是第三种,很明显就上自动机或者是各种字符串匹配算法,这条路应该是可行的,但是我还没想出来。
第2种很明显就是fft了,所以我们考虑用fft;
我们要算的卷积是 c[k]=(a[i]-b[j])^2*b,(i+j=k) 注意当b[i]=='?'时b[i]=0;
然后把公式拆开一项一项算就好了具体见代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const double pi = 3.141592653589793238462643383279502884197169399375105820974944;
char aa[100010], bb[100010];
struct complex
{
double l, r;
complex(double a, double b) :l(a), r(b)
{}
complex(){}
};
complex A[300000], B[300000], C[300000];
int ss1[300000], ss2[300000];
complex operator+(complex a, complex b)
{
return complex(a.l + b.l, a.r + b.r);
}
complex operator-(complex a, complex b)
{
return complex(a.l - b.l, a.r - b.r);
}
complex operator*(complex a, complex b)
{
return complex(a.l*b.l - a.r*b.r, a.l*b.r + a.r*b.l);
}
void rader(complex *a, int len)
{
int j = len >> 1;
for (int i = 1; i < len-1; i++)
{
if (j>i)swap(a[i], a[j]);
int n = len >> 1;
while (n <=j)
j -= n,n>>=1;
j += n;
}
}
void fft(complex *a, int len, int kind)
{
rader(a, len);
for (int l = 1; (1 << l) <= len; l++)
{
int m = 1 << l;
complex wn = complex(cos(2 * kind*pi / m), sin(2 * kind*pi / m));
for (int k = 0; k < len; k += m)
{
complex w = complex(1.0, 0);
for (int j = k; j < k + m / 2; j++)
{
complex ll = a[j];
complex rr = w*a[j + m / 2];
a[j] = ll + rr;
a[j + m / 2] = ll - rr;
w = w*wn;
}
}
}
if (kind == -1)
for (int i = 0; i < len; i++)
a[i].l /= len, a[i].r /= len;
}
int p[260000];
int main()
{
scanf("%s%s", aa, bb);
int lena = strlen(aa);
int lenb = strlen(bb);
int tempb = lenb;
if (lena < lenb)
{
printf("0\n");
return 0;
}
tempb = max(lena, lenb);
int l = 0;
while ((1 << l) < tempb * 2)
l++;
tempb = 1 << l;
for (int i = lena - 1,k=0; i >= 0; i--,k++)
ss1[k]= aa[i] - 'a' + 1;
for (int i = 0; i < lenb; i++)
ss2[i] = (bb[i] == '?' ? 0 : bb[i] - 'a' + 1);
for (int i = 0; i < tempb; i++)
A[i] = complex(ss1[i]*ss1[i]*1.0, 0),
B[i] = complex(ss2[i]*1.0, 0);
fft(A, tempb, 1);
fft(B, tempb, 1);
for (int i = 0; i < tempb; i++)
C[i] = A[i] * B[i];
for (int i = 0; i < tempb; i++)
A[i] = complex(2 * ss1[i]*1.0, 0),
B[i] = complex(ss2[i] * ss2[i]*1.0, 0);
fft(A, tempb, 1);
fft(B, tempb, 1);
for (int i = 0; i < tempb; i++)
C[i] = C[i] - A[i] * B[i];
for (int i = 0; i < tempb; i++)
A[i] = complex(1.0, 0),
B[i] = complex(ss2[i]*ss2[i]*ss2[i]*1.0, 0);
fft(A, tempb, 1);
fft(B, tempb, 1);
for (int i = 0; i < tempb; i++)
C[i] = C[i] + A[i] * B[i];
fft(C, tempb, -1);
int num = 0;
for (int i = lena - 1,k=0; i >= lenb - 1;i--,k++)
{
if (C[i].l < 0.5)
p[num++] = k;
}
printf("%d\n", num);
for (int i = 0; i < num; i++)
printf("%d\n", p[i]);
return 0;
}