• 【CF954I】Yet Another String Matching Problem(FFT)


    【CF954I】Yet Another String Matching Problem(FFT)

    题面

    给定两个字符串(S,T)

    (S)所有长度为(|T|)的子串与(T)的距离

    两个等长的串的距离定义为最少的,将某一个字符全部视作另外一个字符的次数。

    (|T|<=|S|<=10^6),字符集大小为(6)

    题解

    考虑如何快速计算两个串的答案,从左向右扫一遍,如果对应位置上有两个字符不同,检查在并查集中是否属于同一个集合,如果不属于则答案加一,同时合并两个集合。(这个就是CF939D)

    如果枚举每一个长度为(|T|)的子串,复杂度为(O(|S||T|))。考虑优化。

    (T)串反转,枚举两个字符(x,y),将(S)串的(x)字符出现的位置对应为(1),(T)串的(y)字符出现的位置对应为(1),其他对应为(0),然后求两个生成函数的卷积。

    假设在(T)(a)位置和(S)(b)位置对应有(1),那么它们会对(a+b)位置对应一个(1),也就是(b+|T|-a)位置对应一个(1),同时意味着在(S)的从这个位置开始的长度为(|T|)的子串中,这个位置上对应着这两个字符。

    于是枚举每个开始的位置,以及任意两个字符,如果在任意位置这两个字符有对应相等的话,并查集合并即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 333333
    const double Pi=acos(-1);
    struct Complex{double a,b;}A[MAX],B[MAX],W[MAX];
    Complex operator+(Complex a,Complex b){return (Complex){a.a+b.a,a.b+b.b};}
    Complex operator-(Complex a,Complex b){return (Complex){a.a-b.a,a.b-b.b};}
    Complex operator*(Complex a,Complex b){return (Complex){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};}
    int r[MAX],N,n,m,l,eql[MAX][6][6];
    char a[MAX],b[MAX];
    void FFT(Complex *P,int opt)
    {
    	for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
    	for(int i=1;i<N;i<<=1)
    		for(int p=i<<1,j=0;j<N;j+=p)
    			for(int k=0;k<i;++k)
    			{
    				Complex w=(Complex){W[N/i*k].a,W[N/i*k].b*opt};
    				Complex X=P[j+k],Y=w*P[i+j+k];
    				P[j+k]=X+Y;P[i+j+k]=X-Y;
    			}
    }
    int f[6];
    int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
    int main()
    {
    	scanf("%s",a);scanf("%s",b);
    	n=strlen(a),m=strlen(b);
    	for(N=1;N<=(n+m);N<<=1)++l;
    	for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int i=1;i<N;i<<=1)
    		for(int k=0;k<i;++k)W[N/i*k]=(Complex){cos(k*Pi/i),sin(k*Pi/i)};
    	for(int i=0;i<6;++i)
    		for(int j=0;j<6;++j)
    		{
    			for(int k=0;k<N;++k)A[k].a=A[k].b=B[k].a=B[k].b=0;
    			for(int k=0;k<n;++k)A[k].a=(a[k]==i+97);
    			for(int k=0;k<m;++k)B[k].a=(b[m-k-1]==j+97);
    			FFT(A,1);FFT(B,1);
    			for(int k=0;k<N;++k)A[k]=A[k]*B[k];
    			FFT(A,-1);
    			for(int k=0;k<N;++k)eql[k][i][j]=(int)(A[k].a/N+0.5);
    		}
    	for(int i=m-1;i<n;++i)
    	{
    		for(int j=0;j<6;++j)f[j]=j;
    		for(int j=0;j<6;++j)
    			for(int k=0;k<6;++k)
    				if(eql[i][j][k])
    					f[getf(j)]=getf(k);
    		int ans=0;
    		for(int j=0;j<6;++j)if(getf(j)!=j)++ans;
    		printf("%d ",ans);
    	}
    	puts("");
    	return 0;
    }
    
    
  • 相关阅读:
    各种素材类精品网站
    Java如何设置代理ip
    Spring事务的实现方式和原理以及隔离级别?
    Spring 是什么?
    线程池中阻塞队列的作用?为什么是先添加队列而不是先创建最大线程?
    为什么用线程池?解释下线程池参数
    并发三大特性
    ThreadLocal的原理和使用场景。
    谈谈对线程安全的理解
    sleep,wait,join,yield
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8798431.html
Copyright © 2020-2023  润新知