zoukankan      html  css  js  c++  java
  • 【CF472G】Design Tutorial: Increase the Constraints

    Portal --> CF472G

    Description

       给出两个(01)序列(A)(B)

    ​   哈明距离定义为两个长度相同的序列中,有多少个对应位置上的数字不一样(如:(00111)(10101)的距离为2)

    ​   现有(Q)次询问,每次给出(p1,p2,len),求(A[p1...p1+len-1])(B[p2...p2+len-1])两个子串的哈明距离,编号从(0)开始

    数据范围:

    (1<=|A|,|B|<=2*10^5,1<=Q<=4*10^5)(0<=p1<=|A|-len,0<=p2<=|B|-len)

      

    ”Solution“

       这是一篇假题解qwq只是记录一下这种优秀的压位做法(虽然说。。cf上面好像会被卡Q^Q)

       因为没有修改操作之类的东西,串是给定的,所以说我们可以将原串中每一位开始的连续的64位(或者32位压也可以)压成一个unsigned long long(或者long long)

       这样我们可以直接对应的一段取出来异或一下,然后再统计一下异或出来的结果中有多少个(1)就可以知道答案了

       统计的话我们可以预处理一下(1sim 2^{16}-1)的的每一个数写成二进制之后有多少个(1)(记录在(cnt)数组中)然后将异或出来的结果分成(4)段,每段(16)位这样来直接在(cnt)中查,最后将结果累加一下就能够得到答案了

       如果说(64)(64)位分有剩的话,最后一次查询的时候要强行把末尾多余的位去掉(左移一下就好了),时间复杂度是(O(frac{nQ}{64})),不过常数比较小

         

    Solution

       好的接下来的部分是真题解嗯

       考虑分块,块两头暴力比较,块内的预处理一个数组(dis[i][j])表示(A)串中第(i)块整块(长度为(L))和(B)串中(j)开头的长度为(L)的子串的哈明距离

    ​   当然我们可以用上面的那种压位方法来预处理这个(dis)数组,然而很开心T掉了

    ​   注意到因为(L)是固定的(块的长度),所以我们可以用FFT优化一下

    ​   FFT中的(AB)串对应的数组的赋值都是:如果说这个位上的数字为(1)则赋为(1),否则赋为(-1)

       然后将(A)串对应的那个串反过来,做卷积,那么求出来的值就是“同-异”,而整个块的大小(L=)同+异,我们要求的是异,所以直接(同异同异异frac{同+异-(同-异)}{2}=异)

    ​   剩下的是分块的常规操作

       
       mark:计算不同的位置数量的方法记录一下

      

    Code

       压位版本

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ull unsigned long long
    using namespace std;
    const int N=2*(1e5)+10,Div=(1<<16)-1;
    char A[N],B[N];
    ull a[N],b[N],cnt[1<<16];
    int n,m,tot,Q,lena,lenb,ans;
    void prework(){
        for (int i=lena-1;i>=0;--i) a[i]=(a[i+1]>>1)|((ull)(A[i]-'0')<<63);
        for (int i=lenb-1;i>=0;--i) b[i]=(b[i+1]>>1)|((ull)(B[i]-'0')<<63);
        cnt[0]=0;
        for (int i=1;i<1<<16;++i) cnt[i]=cnt[i>>1]+(i&1);
    }
    ull sum(ull x){return cnt[x&Div]+cnt[x>>16&Div]+cnt[x>>32&Div]+cnt[x>>48&Div];}
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
    #endif
        int p1,p2,len;
        scanf("%s",A);lena=strlen(A);
        scanf("%s",B);lenb=strlen(B);
        scanf("%d",&Q);
        prework();
        for (int i=1;i<=Q;++i){
            scanf("%d%d%d",&p1,&p2,&len);
            ans=0;
            for (;len>=64;p1+=64,p2+=64,len-=64)
                ans+=sum(a[p1]^b[p2]);
            if (len)
                ans+=sum((a[p1]^b[p2])>>(64-len));
            printf("%d
    ",ans);
        }
    }
    

       
    ​   分块+FFT版本

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define ll long long
    using namespace std;
    const int N=2e5+10,B=5000,C=N/B+10;
    const double pi=acos(-1);
    struct cmplx{/*{{{*/
    	double a,b;
    	cmplx(){}
    	cmplx(double a1,double b1){a=a1; b=b1;}
    	void init(){a=b=0;}
    	friend cmplx operator + (cmplx x,cmplx y)
    	{return cmplx(x.a+y.a,x.b+y.b);}
    	friend cmplx operator - (cmplx x,cmplx y)
    	{return cmplx(x.a-y.a,x.b-y.b);}
    	friend cmplx operator * (cmplx x,cmplx y)
    	{return cmplx(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);}
    };/*}}}*/
    namespace FFT{/*{{{*/
    	const int TOP=20,N=(1<<18)+10;
    	cmplx A[N],B[N];
    	int rev[N],vis[TOP+1];
    	int len;
    	void get_len(int n){
    		for (int i=0;i<len;++i) A[i].init(),B[i].init();
    		int bit=0;
    		for (len=1;len<=n;++bit,len<<=1);
    		rev[0]=0;
    		for (int i=1;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    	}
    	void clr(int op){
    		for (int i=0;i<len;++i) if (op) B[i].init();else A[i].init();
    	}
    	void fft(cmplx *a,int op){
    		for (int i=0;i<len;++i) 
    			if (rev[i]>i) swap(a[rev[i]],a[i]);
    		cmplx w,u,v,w_n;
    		for (int step=2,k=0;step<=len;step<<=1,++k){
    			w_n=cmplx(cos(2*pi/step),op*sin(2*pi/step));
    			for (int st=0;st<len;st+=step){
    				w=cmplx(1,0);
    				for (int i=0;i<(step>>1);++i){
    					//w=W[k][i]; w.b*=op;
    					v=a[st+i+(step>>1)]*w;
    					u=a[st+i];
    					a[st+i]=u+v;
    					a[st+i+(step>>1)]=u-v;
    					w=w*w_n;
    				}
    			}
    		}
    		if (op==1) return;
    		for (int i=0;i<len;++i) a[i].a/=len;
    	}
    }/*}}}*/
    char a[N],b[N];
    ll dis[C][N];
    int n,m,sq,q,numa,numb;
    ll get_val(cmplx x){return 1LL*round(x.a);}
    int Id(int x){return (x-1)/sq+1;}
    int St(int x){return (x-1)*sq+1;}
    int Ed(int x){return x*sq;}
    void prework(){
    	sq=B;
    
    	int l,r,len;
    	numa=Id(n);
    	numb=Id(m);
    	FFT::get_len(B+m);
    
    	for (int i=1;i<=m;++i) FFT::B[i]=cmplx(b[i]=='1'?1:-1,0);
    	FFT::fft(FFT::B,1);
    	for (int i=1;i<=numa;++i){
    		l=St(i); r=min(Ed(i),n);
    		FFT::clr(0);
    		for (int j=r;j>=l;--j) FFT::A[r-j+1]=cmplx(a[j]=='1'?1:-1,0);
    		FFT::fft(FFT::A,1);
    		for (int j=0;j<FFT::len;++j) FFT::A[j]=FFT::A[j]*FFT::B[j];
    		FFT::fft(FFT::A,-1);
    		len=r-l+1;
    		for (int j=1;j<=m;++j)
    			dis[i][j]=(len-get_val(FFT::A[j+len]))/2;
    	}
    }
    int query(int p1,int p2,int len){
    	int ret=0;
    	int num1=Id(p1),num2=Id(p1+len-1);
    	if (num1==num2){
    		for (int i=0;i<len;++i)
    			ret+=a[p1+i]!=b[p2+i];
    	}
    	else{
    		for (int i=p1;i<=Ed(num1);++i)
    			ret+=a[i]!=b[p2+i-p1];
    		for (int i=num1+1;i<num2;++i)
    			ret+=dis[i][p2+St(i)-p1];
    		for (int i=St(num2);i<=p1+len-1;++i)
    			ret+=a[i]!=b[p2+i-p1];
    	}
    	return ret;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int p1,p2,len;
    	scanf("%s",a+1);
    	scanf("%s",b+1);
    	n=strlen(a+1); m=strlen(b+1);
    	prework();
    	scanf("%d",&q);
    	for (int i=1;i<=q;++i){
    		scanf("%d%d%d",&p1,&p2,&len);
    		++p1; ++p2;
    		printf("%d
    ",query(p1,p2,len));
    	}
    }
    
  • 相关阅读:
    OLAP ODS项目的总结 平台选型,架构确定
    ORACLE ORA12520
    ORACLE管道函数
    ORACLE RAC JDBC 配置
    ORACLE RAC OCFS连接产生的错误
    ORACLE 启动和关闭详解
    OLAP ODS项目的总结 起步阶段
    ORACLE RAC 配置更改IP
    ORACLE RAC OCR cann't Access
    ORACLE RAC Debug 之路 CRS0184错误与CRS初始化
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9407972.html
Copyright © 2011-2022 走看看