zoukankan      html  css  js  c++  java
  • 【题解】2021HDU多校第三场 HDU6975 Forgiving matching

    2021HDU多校第三场 HDU6975 Forgiving matching

    题意

    给一个串(A),和串(B)(均仅含字符'1'-'9'或通配符'*'),其中通配符可以匹配任意字符,分别求出最多容许(k)个字符失配的情况下((0le kle m)),有多少个(A)的子串和(B)匹配。

    (1le |B|le |A|le 2 imes 10^5,sum|A|le 10^6)

    题解

    做法类似于Fuzzy search。两个字符匹配当且仅当它们字符相等,或者至少有一个是通配符。由于需要求出(A)中每个长度为(m)的子串有多少个位置与(B)串匹配,我们可以对每个字符分开处理.对于数字字符(c),我们将(A,B)中为(c)的位置置为1,其他位置置为0,翻转(B)串后做(FFT),则(a_i)即为(A)中以(i)结尾的长度为(m)的子串有多少个位置的(c)字符和(B)串对应位置的(c)字符匹配。对于通配符,通过通配符匹配的位置数即为(A的长度为m的子串中通配符的个数+B中通配符的个数-对应位置都是通配符的个数),将上述两种情况相加后即得到(A)中每个长度为(m)的子串有多少个位置与(B)串匹配,即可求答案。

    #include <bits/stdc++.h>
    typedef double db;
    typedef long long ll;
    using namespace std;
    const double pi=acos(-1.0);
    const int N=2300005;
    int r[N];
    struct cpl{
    	db x,y;
    	cpl operator +(const cpl & bb)const{return (cpl){x+bb.x,y+bb.y};}
    	cpl operator -(const cpl & bb)const{return (cpl){x-bb.x,y-bb.y};}
    	cpl operator *(const cpl & bb)const{return (cpl){x*bb.x-y*bb.y,x*bb.y+y*bb.x};}
    	cpl operator /(const db &bb)const{return (cpl){x/bb,y/bb};}
    }a[N],b[N];
    void fft(cpl *a,int lim,int typ){
    	for(int i=0;i<=lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
    	for(int mid=1;mid<lim;mid<<=1){
    		cpl w1=(cpl){cos(pi/mid),typ*sin(pi/mid)};
    		for(int  R=mid<<1,j=0;j<lim;j+=R){
    			cpl w=(cpl){1,0};
    			for(int i=0;i<mid;i++,w=w*w1){
    				cpl y=a[i+j+mid]*w;
    				a[i+j+mid]=a[i+j]-y;a[i+j]=a[i+j]+y;
    			}
    		}
    	}
    	if(typ==-1){
    		for(int i=0;i<=lim;i++)a[i].x/=lim;
    		for(int i=0;i<=lim;i++)a[i].y/=lim;
    	}
    }
    int lim=0,l=0,n,m;
    int f[N],s1[N],s2[N],ans[N];
    void f1(){
    	string A,B;
    	cin>>n>>m;
    	cin>>A>>B;
    	s1[0]=(A[0]=='*');s2[0]=(B[0]=='*');
    	for(int i=0;i<=n;i++){f[i]=0;ans[i]=0;}
    	for(int i=1;i<n;i++){s1[i]=s1[i-1]+(A[i]=='*');}
    	for(int i=1;i<m;i++){s2[i]=s2[i-1]+(B[i]=='*');ans[i]=0;}
    	lim=1;l=0;while(lim<=(n+m)){lim<<=1;++l;}
    	for(int i=0;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int o=0;o<10;o++){
    		char c='0'+o;
    		for(int i=0;i<=lim;i++){a[i].x=a[i].y=0;b[i].x=b[i].y=0;}
    		for(int i=0;i<n;i++){
    			if(A[i]==c){a[i].x=1;}
    		}
    		for(int i=0;i<m;i++){
    			if(B[i]==c){a[m-1-i].y=1;}
    		}
    		fft(a,lim,1);
    		for(int i=0;i<=lim;i++){a[i]=a[i]*a[i];}
    		fft(a,lim,-1);
    		for(int i=m-1;i<n;i++){f[i]+=(int)(0.5+a[i].y/2.0);}
    	}
    	
    	{ //处理通配符 
    		char c='*';
    		for(int i=0;i<=lim;i++){a[i].x=a[i].y=0;b[i].x=b[i].y=0;}
    		for(int i=0;i<n;i++){
    			if(A[i]==c){a[i].x=1;}
    		}
    		for(int i=0;i<m;i++){
    			if(B[i]==c){a[m-1-i].y=1;}
    		}
    		fft(a,lim,1);
    		for(int i=0;i<=lim;i++){a[i]=a[i]*a[i];}
    		fft(a,lim,-1);
    		int ns=s2[m-1];
    		for(int i=m-1;i<n;i++){
    			if(i==m-1){
    				f[i]+=s1[i]+ns-(int)(0.5+a[i].y/2.0);
    			}
    			else{
    				f[i]+=s1[i]-s1[i-m]+ns-(int)(0.5+a[i].y/2.0);
    			}
    		}
    	} 
    	for(int i=m-1;i<n;i++){
    		ans[m-f[i]]++;
    	}
    	for(int i=1;i<=m;i++){
    		ans[i]+=ans[i-1];
    	}
    	for(int i=0;i<=m;i++){
    		cout<<ans[i]<<"
    ";
    	}
    }
    int main(){
    	std::ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	int t;cin>>t;
    	while(t--)
    		f1();
    	return 0;
    }
    
    
  • 相关阅读:
    Queue——C#浅谈
    C#设计模式(7)——适配器模式
    test
    python 技巧
    在centos 配置python django环境 总结
    pyqt5 做的小程序,可以用来UI做个小demo
    python sqlalthemy 总结
    数据清理,预处理 pandas dataframe 操作技巧 总结
    对区块链看法
    hadoop spark 总结
  • 原文地址:https://www.cnblogs.com/bobh/p/15074752.html
Copyright © 2011-2022 走看看