bzoj4503

体会一下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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值