ural1996:KMP + FFT

ural 1996

题解

  • 只有最后一个数字可以修改,所以我们把最后一个单独那出来。比如A串单独拿出来为1 0 1 1 0 1,B串为1 0 0。那么对于第i个位置,我们可以计算从第i-m+1个位置开始至此,共有多少个01不匹配。上面这个为 1 1 1 3 1 1,记做res[N];
  • 我们可以先计算A串为1,B串为0,有多少不匹配。再计算A串为0,B串为1有多少不匹配。再相加。
  • 对于第一种情况,我们可以翻转B串的01,便得到0 1 1。我们可以先和1 0 1比较,发现最后一个对上了,所以结果为1。和0 1 1倒数两个对上了,所以结果为2。我们有更快捷的方法,反转0 1 1得到1 1 0。这样子1 0 1的最后一个1实际上和1 1 0的第一个要匹配。变成多项式就为(1 + 0^x1 + x^2)(1 + x + 0x^2)这样x^2的系数为1。同理第二个,(0 + x^1 + x^2)(1 + x^1 + 0),x^3的系数为2。用FFT可以快速处理。
  • 最后把前7位拿出来进行KMP算法,匹配上的再比较res[N]。

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 250000 + 10;
int const inf = 0x7f7f7f7f;
double const pi = acos(-1.0);
int n,m,rev[N<<2],res[N<<2];
int s1[N],s2[N],ne[N];
struct Complex{
    double x,y;
    Complex(){}
    Complex(double x,double y):x(x),y(y){}
    Complex(double x):x(x),y(0.0){}
    Complex operator + (const Complex &e) const{
        return Complex(x + e.x,y + e.y);
    }
    Complex operator - (const Complex &e) const{
        return Complex(x - e.x,y - e.y);
    }
    Complex operator * (const Complex &e) const{
        return Complex(x * e.x- y * e.y,x * e.y + y * e.x);
    }
    Complex operator / (const Complex &e) const{
       double m = e.x * e.x-e.y * e.y;
       return Complex((x * e.x + y * e.y) / m,(y * e.x-x * e.y) / m);
    }
}a[N<<2],b[N<<2];
void FFT(Complex *a,int n,int inv){
    int bit = 0;
    while((1<<bit)<n)   bit++;
    for(int i=0;i<n;i++){
        rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));  
        if(i<rev[i])    swap(a[i],a[rev[i]]);
    }
    for(int mid=1;mid<n;mid*=2){   
        Complex temp(cos(pi/mid),inv*sin(pi/mid)); 
        for(int i=0;i<n;i+=mid*2){
            Complex omega(1,0);
            for(int j=0;j<mid;j++,omega=omega*temp){
                Complex x=a[i+j],y=omega * a[i+j+mid]; 
                a[i+j] = x + y,a[i+j+mid] = x-y;  
            }
        }
    }
}
void Cacl(int x,int y){   //s1串为1,s2串为0的个数
	int len;
	for(len=1;len<=n+m;len<<=1);
	for(int i=0;i<=len;i++){
		if(i < n && (s1[i]&1) == x)	a[i] = Complex(1,0);
		else a[i] = Complex(0,0);
		if(i < m && (s2[m-i-1]&1) == y)	b[i] = Complex(1,0);
		else b[i] = Complex(0,0);
	}
	FFT(a,len,1);	FFT(b,len,1);
	for(int i=0;i<=len;i++)	a[i] = a[i] * b[i];
	FFT(a,len,-1);
	for(int i=0;i<=len;i++)	res[i] += (int)(a[i].x / len + 0.5);
}
void get_ne(int s[N],int len){    //找前缀数组
	memset(ne,0,sizeof(ne));
	ne[0] = -1;
	int i = 0,k = -1;       //j从-1开始可以排除第一个数的干扰
  	while(i < len){  
		if(k == -1 || s[i] == s[k])	ne[++i] = ++k;
		else	k = ne[k];
	}
}
void KMP(int p[N],int s[N],int len1,int len2){
	int i = 0,j = 0,ans = inf,pos;
	while(i < len1  && j < len2){
		if(j == -1 || p[i] == s[j])	i++,	j++;
		else	j = ne[j];
		if(j == len2){
			if(ans > res[i-1]){ 
				ans = res[i-1];
				pos = i - j + 1;
			}
			j = ne[j];
		}
	}
	if(ans == inf)	printf("No\n");
	else{
		printf("Yes\n");
		printf("%d %d\n",ans,pos);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)	scanf("%d",&s1[i]);
	for(int i=0;i<m;i++)	scanf("%d",&s2[i]);
	Cacl(1,0); 
	Cacl(0,1);
	for(int i=0;i<n;i++)	s1[i] /= 10;
	for(int i=0;i<m;i++)	s2[i] /= 10;
	get_ne(s2,m);
	KMP(s1,s2,n,m);
}	 

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/89514840
FFT