bzoj4259: 残缺的字符串

Posted thy_asdf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4259: 残缺的字符串相关的知识,希望对你有一定的参考价值。

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4259

思路:FFT是一种高效的字符串匹配算法

只要想到FFT就好办了

令为‘*’的位置值为0

那么两个字符串匹配当且仅当

Σ(a[i]-b[i])^2*a[i]*b[i]=0

式子的含义很好理解,前面就是字符相同,后面就是该位是否为通配符

为了FFT能做,我们要把A串反过来才有一个卷积的形式

设F[i]就是B串以i结尾的子串B[i-m+1,i]与A匹配得到的值

f[i]=Σ(a[j]-b[i-j])^2*a[j]*b[i-j]

    =Σ(a[j]^3*b[i-j]-2*(a[j])^2*(b[i-j])^2)+a[j]*b[i-j]^3)

分成三个部分,分别做FFT,加起来就是答案了

(公式写的比较挫,可以去看claris的博客http://www.cnblogs.com/clrs97/p/4814499.html

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=300010,maxt=(1<<19)+10;
using namespace std;
int n,m,ans[maxn],a[maxn],b[maxn];char s1[maxn],s2[maxn];
struct comdouble r,i;A[maxt],B[maxt],C[maxt];
com operator +(com a,com b)return (com)a.r+b.r,a.i+b.i;
com operator -(com a,com b)return (com)a.r-b.r,a.i-b.i;
com operator *(com a,com b)return (com)a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r;
com operator /(com a,int b)return (com)a.r/b,a.i/b;
com operator *(com a,int b)return (com)a.r*b,a.i*b;
double sqr(int x)return x*x;
double cube(int x)return x*x*x;

struct FFT
	int rev[maxt],n;
	void clear(com a[])memset(a,0,sizeof(*a)*(n+1));
	void init(int nn)
		for (n=1;n<nn;n<<=1);
		for (int i=1;i<n;i++) rev[i]=rev[i-(i&-i)]+(n>>1)/(i&-i);
	
	void fft(com a[],int op)
		for (int i=1;i<n;i++) if (rev[i]<i) swap(a[rev[i]],a[i]);
		for (int sz=2;sz<=n;sz<<=1)
			com w0=(com)cos(2*M_PI/sz),sin(2*M_PI*op/sz);
			for (int bg=0;bg<n;bg+=sz)
				com w=(com)1,0;
				for (int pos=bg;pos<bg+(sz>>1);pos++)
					com x=a[pos],y=w*a[pos+(sz>>1)];
					a[pos]=x+y,a[pos+(sz>>1)]=x-y;
					w=w*w0;
				
			
		
		if (op==-1) for (int i=0;i<n;i++) a[i]=a[i]/n;
	
T;

void init()
	scanf("%d%d",&m,&n);
	scanf("%s%s",s1,s2);
	for (int i=0;i<m;i++) a[i]=s1[i]=='*'?0:s1[i]-'a'+1;
	for (int i=0;i<n;i++) b[i]=s2[i]=='*'?0:s2[i]-'a'+1;
	for (int i=0;i<(m>>1);i++) swap(a[i],a[m-i-1]);
	//for (int i=0;i<m;i++) printf("%d ",(int)a[i]);puts("");
	//for (int i=0;i<n;i++) printf("%d ",(int)b[i]);puts("");


void work()
	T.init(n);
	
	T.clear(A),T.clear(B);
	for (int i=0;i<m;i++) A[i]=(com)a[i],0;
	for (int i=0;i<n;i++) B[i]=(com)cube(b[i]),0;
	T.fft(A,1),T.fft(B,1);
	for (int i=0;i<T.n;i++) C[i]=C[i]+A[i]*B[i];
	//for (int i=0;i<T.n;++i) printf("r=%.3lf i=%.3lf\\n",C[i].r,C[i].i);puts("");
	
	T.clear(A),T.clear(B);
	for (int i=0;i<m;i++) A[i]=(com)sqr(a[i]),0;
	for (int i=0;i<n;i++) B[i]=(com)sqr(b[i]),0;
	T.fft(A,1),T.fft(B,1);
	for (int i=0;i<T.n;i++) C[i]=C[i]-A[i]*B[i]*2;
	//for (int i=0;i<T.n;++i) printf("r=%.3lf i=%.3lf\\n",C[i].r,C[i].i);puts("");
	
	T.clear(A),T.clear(B);
	for (int i=0;i<m;i++) A[i]=(com)cube(a[i]),0;
	for (int i=0;i<n;i++) B[i]=(com)b[i],0;
	T.fft(A,1),T.fft(B,1);
	for (int i=0;i<T.n;i++) C[i]=C[i]+A[i]*B[i];
	//for (int i=0;i<T.n;++i) printf("r=%.3lf i=%.3lf\\n",C[i].r,C[i].i);puts("");
	
	T.fft(C,-1);
	int cnt=0;
	for (int i=0;i<n-m+1;i++)
		if (fabs(C[m-1+i].r)<1e-1)
			ans[++cnt]=i+1;
	printf("%d\\n",cnt);
	for (int i=1;i<cnt;i++) printf("%d ",ans[i]);
	printf("%d\\n",ans[cnt]);


int main()
	init(),work();
	return 0;



以上是关于bzoj4259: 残缺的字符串的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4259 4259: 残缺的字符串FFT

BZOJ4259: 残缺的字符串

BZOJ4259 残缺的字符串 多项式 FFT

@bzoj - 4259@ 残缺的字符串

BZOJ 4259 残缺的字符串 ——FFT

Bzoj4259 残缺的字符串