• cf 472G Design Tutorial: Increase the Constraints 分块+压位/FFT


    题目大意

    给出两个(01)序列(A)(B)
    哈明距离定义为两个长度相同的序列中,有多少个对应位置上的数字不一样
    "00111" 和 "10101"的距离为2
    (Q)次询问,每次询问给出(p_1,p_2,len)
    (a{p_1},a{p_1+1}...a_{p_1+len-1})(b_{p_1},b_{p_1+1}...b_{p_1+len-1})两个子串的哈明距离
    注意:本题中的序列是从(0)开始编号的:(a_0,a_1,...,a_{n-1})
    (1leq |A|.|B|leq 2*10^5,1leq Qleq 4*10^5)
    (0 leq p_1 leq |a| - len),(0 leq p_2 leq |b| - len)

    分析

    哈明距离可以转化成异或后有多少个(1)
    考虑如何快速的比较两个字符串
    我们先求出每个位置往后(32)位/(64)位的压位后的值
    这样之后再暴力的复杂度就变成了(frac {len} {32})
    我们再考虑对(A)串分块
    每长度(T)分一块
    预处理(dif[i][j])表示(A)中第(i)块整个块 和 (B)(j)开始的长度为(T)的串的哈明距离
    (O(frac n T *m *frac T {32})=O(frac {n*m} {32}))
    对于询问
    左右两边暴力扫(O(T))
    中间块内的用预处理直接求(O(frac n T))
    算出来(T=sqrt n)最优
    同时T要是(32)/(64)的倍数
    原题空间256M好像开不到(n*sqrt n)的数组要调调参数

    优化

    块内的复杂度(O(frac {n*m} {32}))小心脏承受不住
    可以用FFT优化
    s[i]==1的FFT数组中设为1,否则设为-1
    将块中串反过来,卷积一波
    求出来的值就是(同-异)
    而块的大小为(同+异)
    (frac {同+异-(同-异)} 2=异)
    这样就可以不用1算一次,0算一次再用总数减常数那么大了
    结果越跑越慢
    各种调参数到5000左右最快了

    组合

    如果两个算法合起来就完美了(越写越慢还好意思说)

    注意

    unsigned满位后左移一位可以看作把最高位扔掉后左移一位
    bitset的count()是暴力
    正确姿势:预处理1<<16内每个数有多少个1,分段算
    FFT有负数用round()取整

    solution(分块+压位)

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <bitset>
    using namespace std;
    typedef unsigned long long ull;
    const int S=450;
    const int M=200003;
    const int N=1<<16;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    char s[M];
    char t[M];
    int n,m,Q;
    int sn,MX;
    int cnt[N];
    ull aw[M],bw[M];
    int dif[S][M];
    
    int loc(int x){
    	return x/sn+1;
    }
    
    int getL(int x){
    	return (x-1)*sn;
    }
    
    int getR(int x){
    	return x*sn-1;
    }
    
    int getP(int x){
    	int L=getL(loc(x));
    	return x-L+1;
    }
    
    int main(){
    	int i,j,k,BL,BR,L,R,x,y,z,len;
    	
    	scanf("%s%s",s,t);
    	n=strlen(s); m=strlen(t);
    	sn=448; MX=loc(n);
    	
    	for(i=0;i<N;i++) cnt[i]=cnt[i>>1]+(i&1);
    	
    	for(i=0;i+63<n;i++)
    		for(j=i;j<i+64;j++)
    			aw[i]=aw[i]<<1|(s[j]=='1');
    	
    	for(i=0;i+63<m;i++)
    		for(j=i;j<i+64;j++)
    			bw[i]=bw[i]<<1|(t[j]=='1');
    	
    	int ful=N-1;
    	for(i=1;i<=MX;i++){
    		L=getL(i);
    		if(L+sn-1>=n) break;
    		for(j=0;j+sn-1<m;j++){
    			x=L,y=j;
    			for(k=7;k>0;k--){
    				ull tp=aw[x]^bw[y];
    				dif[i][j]+=cnt[tp&ful]+cnt[tp>>16&ful]+cnt[tp>>32&ful]+cnt[tp>>48];
    				x+=64; y+=64;
    			}
    		}
    	}
    	
    	Q=rd();
    	
    	int ans;
    	while(Q--){
    		ans=0;
    		x=rd(),z=rd(),len=rd();
    		y=x+len-1;
    		BL=loc(x); BR=loc(y);
    		if(BL+1>=BR){
    			for(i=x;i<=y;i++) ans+=s[i]!=t[z+i-x];
    		}
    		else{
    			if(getL(BL)!=x) BL++;
    			if(getR(BR)!=y) BR--;
    			L=getL(BL); R=getR(BR);
    			for(i=BL;i<=BR;i++)
    				ans+=dif[i][z+getL(i)-x];
    			for(i=x;i<L;i++) ans+=s[i]!=t[z+i-x];
    			for(i=y;i>R;i--) ans+=s[i]!=t[z+i-x];
    		}
    		printf("%d
    ",ans);
    	}
    	
    	return 0;
    }
    

    solution(分块+FFT)

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef double db;
    const int N=262144;
    const int S=207;
    const int M=200003;
    const db pi=acos(-1.0);
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    char s[M];
    char t[M];
    int rev[N];
    int n,m,Q;
    int sn,MX;
    
    struct CP{
    	db x,i;
    	CP(db xx=0.0,db ii=0.0){x=xx;i=ii;}
    }a[N],b[N],c[N];
    CP operator +(CP x,CP y){return CP(x.x+y.x,x.i+y.i);}
    CP operator -(CP x,CP y){return CP(x.x-y.x,x.i-y.i);}
    CP operator *(CP x,CP y){return CP(x.x*y.x-x.i*y.i,x.i*y.x+x.x*y.i);}
    
    void FFT(CP *a,int fl){
    	int i,j,k;
    	CP W,Wn,u,v;
    	for(i=0;i<N;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
    	
    	for(i=2;i<=N;i<<=1){
    		Wn=CP(cos(2*pi/i),fl*sin(2*pi/i));
    		for(j=0;j<N;j+=i){
    			W=CP(1,0);
    			for(k=j;k<j+i/2;k++,W=W*Wn){
    				u=a[k];
    				v=a[k+i/2]*W;
    				a[k]=u+v;
    				a[k+i/2]=u-v;			
    			}
    		}
    	}
    	if(fl==1) return ;
    	for(i=0;i<N;i++) a[i].x/=N;
    }
    
    int dif[S][M];
    
    int loc(int x){
    	return x/sn+1;
    }
    
    int getL(int x){
    	return max(1,(x-1)*sn);
    }
    
    int getR(int x){
    	return min(n,x*sn-1);
    }
    
    int getP(int x){
    	int L=getL(loc(x));
    	return x-L+1;
    }
    
    int main(){
    	int i,j,BL,BR,L,R,x,y,z,len;
    	
    	scanf("%s%s",s+1,t+1);
    	n=strlen(s+1); m=strlen(t+1);
    	sn=5000; MX=loc(n);
    	
    	for(i=0;i<N;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?(N>>1):0);
    	for(i=1;i<=m;i++) b[i]=(t[i]=='1')?1:-1;
    	FFT(b,1);
    	
    	for(i=1;i<=MX;i++){
    		L=getL(i);
    		R=getR(i);
    		for(j=0;j<N;j++) a[j]=CP();
    		int tt=0;
    		for(j=R;j>=L;j--) a[++tt]=(s[j]=='1')?1:-1;
    		FFT(a,1);
    		
    		for(j=0;j<N;j++) c[j]=a[j]*b[j];
    		FFT(c,-1);
    		int sss=R-L+1;
    		for(j=1;j<=m;j++) dif[i][j]=(sss-round(c[j+sss].x))/2;
    	}
    		
    	Q=rd();
    	
    	int ans;
    	while(Q--){
    		ans=0;
    		x=rd(),z=rd(),len=rd();
    		x++;z++;//ÎÒ´Ó 1 ´æ 
    		y=x+len-1;
    		BL=loc(x);BR=loc(y);
    		if(BL+1>=BR){
    			for(i=x;i<=y;i++) ans+=(s[i]!=t[z+i-x]);
    		}
    		else{
    			if(getL(BL)!=x) BL++;
    			if(getR(BR)!=y) BR--; 
    			L=getL(BL); R=getR(BR);
    			for(i=x;i<L;i++) ans+=(s[i]!=t[z+i-x]);
    			for(i=BL;i<=BR;i++)
    				ans+=dif[i][z+getL(i)-x];
    			for(i=y;i>R;i--) ans+=(s[i]!=t[z+i-x]);
    		}
    		printf("%d
    ",ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    .NET面试题系列(五)数据结构(Array、List、Queue、Stack)及线程安全问题
    一个使用 Go 的思维来帮助您构建并开发 Go 应用程序的开源框架
    UML类图学习
    服务器防攻击手段
    .NET面试题系列(四)计算机硬件知识
    .NET面试题系列(三)排序算法
    ASP.NET MVC学习(五)之MVC原理解析
    socketWriter.go
    multiWriter.go
    timeCache.go
  • 原文地址:https://www.cnblogs.com/acha/p/6441079.html
Copyright © 2020-2023  润新知