zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Leetcode-2 两数相加
    离散数学-基本割集的找法
    Linux操作系统分析课程学习总结报告
    Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程
    Linux实验二:深入理解系统调用
    初始python
    水仙花数讲解
    Python-运算
    Python-列表
    Python-字符串
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10163622.html
Copyright © 2011-2022 走看看