URAL 1996. Cipher Message 3(KMP+fft)

传送门

解题思路

  因为要完全匹配,所以前七位必须保证相同,那么就可以把前7位提出来做一遍(kmp)匹配,最后的答案一定在这些位置里。考虑最后一位,可以把最后一位单独取出来,要计算的是最后一位相同的个数,那么就可以做两次(fft)得到(haming dis)。先把(b)翻转,然后做一次,得到的是全为(1)的个数,再把(a,b)取反做一次,得到的是全为(0)的个数,然后扫一遍(kmp)后的匹配位置,取个最小值。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>

using namespace std;
const int MAXN = 1000005;
const double Pi = acos(-1);

int a[MAXN],b[MAXN],pos[MAXN],p[MAXN],rev[MAXN],id,n,m;
int nxt[MAXN],cnt,limit=1,c[MAXN],d[MAXN],ans=1e9;
struct Complex{
	double x,y;
	Complex(double _x=0,double _y=0){x=_x;y=_y;}	
}f[MAXN],g[MAXN];

Complex operator+(Complex A,Complex B){return Complex(A.x+B.x,A.y+B.y);}
Complex operator-(Complex A,Complex B){return Complex(A.x-B.x,A.y-B.y);}
Complex operator*(Complex A,Complex B){return Complex(A.x*B.x-A.y*B.y,A.x*B.y+A.y*B.x);}

void fft(Complex *f,int type){
	for(int i=0;i<limit;i++) if(i<rev[i]) swap(f[i],f[rev[i]]);
	Complex Wn,w,tmp;int len;
	for(int i=2;i<=limit;i<<=1){
		len=i>>1;Wn=Complex(cos(Pi/len),type*sin(Pi/len));
		for(int j=0;j<limit;j+=i){
			w=Complex(1,0);
			for(int k=j;k<j+len;k++){
				tmp=w*f[k+len];f[k+len]=f[k]-tmp;
				f[k]=f[k]+tmp;w=w*Wn;
			}
		}
	}
}

inline void get_nxt(){
	for(int i=2,j=0;i<=m;i++){
		while(j>0 && b[i]!=b[j+1]) j=nxt[j];
		if(b[i]==b[j+1]) j++;
		nxt[i]=j;
	}
}	

inline void get_match(){
	for(int i=1,j=0;i<=n;i++){
		while(j>0 && a[i]!=b[j+1]) j=nxt[j];
		if(a[i]==b[j+1]) j++;
		if(j==m) pos[++cnt]=i-m+1,j=nxt[j];
	}
}

inline void get_init(){
	while(limit<=n+m) limit<<=1;
	for(int i=0;i<limit;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?limit>>1:0);	
}

inline void get_ans(){
	for(int i=0;i<n;i++) f[i].x=c[i],f[i].y=0;
	for(int i=0;i<m;i++) g[i].x=d[i],g[i].y=0;
	for(int i=n;i<limit;i++) f[i].x=f[i].y=0;
	for(int i=m;i<limit;i++) g[i].x=g[i].y=0;
	fft(f,1);fft(g,1);
	for(int i=0;i<limit;i++) f[i]=f[i]*g[i];
	fft(f,-1);
	for(int i=0;i<=n-m;i++) p[i]+=(int)(f[i+m-1].x/limit+0.5); 	
}

int main(){
	scanf("%d%d",&n,&m);char s[10];
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=7;j++) 
			a[i]=(a[i]<<1)+(s[j]-'0');
		c[i-1]=s[8]-'0';
	}
	for(int i=1;i<=m;i++){
		scanf("%s",s+1);
		for(int j=1;j<=7;j++)
			b[i]=(b[i]<<1)+(s[j]-'0');
		d[m-i]=s[8]-'0';	
	}
	get_nxt();get_match();
	if(!cnt) puts("No");
	else{
		puts("Yes");
		get_init();get_ans();
		for(int i=0;i<n;i++) c[i]^=1;
		for(int i=0;i<m;i++) d[i]^=1;
		get_ans();
		for(int i=1;i<=cnt;i++)	
			if(m-p[pos[i]-1]<ans) {	
				ans=m-p[pos[i]-1];
				id=pos[i];	
			}
		printf("%d %d",ans,id);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/10163622.html