• CF472G Increase the Constraints


    Increase the Constraints

    定义两个等长的01字符串的汉明距离为它们字符不同的对应位置的个数。

    给你两个01串S,T,现在有q个询问,每次指定S,T中两个定长的子串询问它们的汉明距离。

    1≤|S|,|T|≤200000,1≤q≤400000

    cz_xuyixuan的题解

    字符不同=长度-字符相同。考虑到两个字符串的匹配问题可以用FFT处理,于是往FFT方面考虑。

    分块FFT,令分块大小为B,进行O((frac{n}{B}))次FFT,处理出O((frac{n}{B}))个T的后缀与S的每个后缀能够匹配的位数。询问时容斥一下并加上边角暴力就好了。

    这样的时间复杂度是O((frac{n^2log n}{B})+qB),取B=n(sqrt{frac{log n}{q}})=‭1,327.013205时,可以获得渐进意义下最优复杂度O(n(sqrt{q log n}))。

    有一种高妙的做法来解决01匹配问题。我们令0为1,1为-1,然后FFT。那么两个字符如果匹配,得数为1,否则为-1。我们给1和-1的总和加上长度,那么就变成了匹配得2,不匹配得0.

    由于NTT常数大,所以程序取B=7200。

    CO int N=524288;
    int rev[N],omg[N];
    
    void NTT(int a[],int lim,int dir){
    	for(int i=0;i<lim;++i)
    		if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int i=1;i<lim;i<<=1)
    		for(int j=0;j<lim;j+=i<<1)
    			for(int k=0;k<i;++k){
    				int t=mul(omg[lim/(i<<1)*k],a[j+i+k]);
    				a[j+i+k]=add(a[j+k],mod-t),a[j+k]=add(a[j+k],t);
    			}
    	if(dir==-1){
    		int ilim=fpow(lim,mod-2);
    		for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
    	}
    }
    
    CO int B=7200;
    char s[N],t[N];int ls,lt;
    int index[N],l[N],r[N],tot;
    int a[N],b[N],ans[N/B][N];
    
    int query(int ps,int pt){
    	int ans=0;
    	if(ps+B>=ls or pt+B>=lt){
    		for(;ps<ls and pt<lt;++ps,++pt) ans+=s[ps]==t[pt];
    		return ans;
    	}
    	for(;index[pt]==index[pt-1];++ps,++pt) ans+=s[ps]==t[pt];
    	ans+=::ans[index[pt]][ps];
    	return ans;
    }
    int main(){
    	scanf("%s%s",s,t);
    	ls=strlen(s),lt=strlen(t);
    	for(int i=0;i<lt;++i){
    		if(i%B==0) l[++tot]=i;
    		index[i]=tot,r[tot]=i;
    	}
    	for(int p=1;p<=tot;++p){
    		memset(a,0,sizeof a);
    		for(int i=0;i<ls;++i) a[i]=s[i]=='0'?1:mod-1;
    		memset(b,0,sizeof b);
    		for(int i=l[p];i<lt;++i) b[lt-1-i]=t[i]=='0'?1:mod-1;
    		int n=lt-l[p]-1;
    		
    		int len=ceil(log2(ls+n)),lim=1<<len;
    		for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
    		omg[0]=1,omg[1]=fpow(3,(mod-1)/lim);
    		for(int i=2;i<lim;++i) omg[i]=mul(omg[i-1],omg[1]);
    		NTT(a,lim,1),NTT(b,lim,1);
    		for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    		omg[1]=fpow(omg[1],mod-2);
    		for(int i=2;i<lim;++i) omg[i]=mul(omg[i-1],omg[1]);
    		NTT(a,lim,-1);
    		
    		for(int i=0;i<ls;++i){
    			ans[p][i]=add(a[i+n],add(n+1,mod-max(0,i+n-ls+1))); // edit 1
    			ans[p][i]=mul(ans[p][i],i2);
    		}
    	}
    	for(int q=read<int>();q--;){
    		int ps=read<int>(),pt=read<int>(),n=read<int>();
    		printf("%d
    ",n-query(ps,pt)+query(ps+n,pt+n));
    	}
    	return 0;
    }
    

    处理ans数组的时候还是要放到模意义下,因为1和-1的总和可能为负数。

  • 相关阅读:
    电脑使用优化工具方法
    算法练习的网站
    golang 实现链表反转打印
    刷过的算法题
    Symfony2框架实战教程——第六天#Alt:验证码
    Symfony2框架实战教程——第六天:模板重载与翻译
    [Symfony2] 在命令或控制器里跑另一个命令的N种方法
    Symfony2框架实战教程——第五天:KnpMenuBundle创建菜单项+结合Twitter Boostrap3
    Symfony2框架实战教程——第四天#Alt:用FOSUserBundle实现用户注册和登录
    Symfony2框架实战教程——第四天:用HWIOAuthBundle实现第三方登录
  • 原文地址:https://www.cnblogs.com/autoint/p/12027371.html
Copyright © 2020-2023  润新知