zoukankan      html  css  js  c++  java
  • CodeForces914G Sum the Fibonacci

    题面

    这是一道FWT好题!

    虽然更多的人应该觉得这是个简单套路题

    但是正因为经典才能成为套路不是吗?

    FWT统计方案数

    (cnt[i])表示(S_x=i)的方案数

    (A[i])表示(S_a|S_b=i)(S_a & S_b=0)的方案数

    B[i]表示(S_a=i)的方案数(就是(cnt[i ]))

    (C[i])表示(S_a oplus S_b=i)

    算出方案数再乘上对应的斐波那契数

    最后再与卷积

    统计(2^i)的答案即可

    话说我发现FWT跑得比FMT

    (170)个测试点差了(4s)

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define gc c=getchar()
    #define r(x) read(x)
    #define ll long long 
    
    template<typename T>
    inline void read(T&x){
    	x=0;T k=1;char gc;
    	while(!isdigit(c)){if(c=='-')k=-1;gc;}
    	while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
    }
    
    const int len=1<<17;
    const int N=len|7;
    const int p=1e9+7;
    const int Inv2=(p+1)>>1;
    
    inline int add(int a,int b){
    	a+=b;
    	if(a>=p)a-=p;
    	return a;
    }
    
    inline int sub(int a,int b){
    	a-=b;
    	if(a<0)a+=p;
    	return a;
    }
    
    inline void FWT_or(int *A,bool opt=1){
    	for(int i=1;i<len;i<<=1){
    		for(int j=0;j<len;j+=i<<1){
    			for(int k=0;k<i;++k){
    				A[j+k+i]=opt?add(A[j+k],A[j+k+i]):sub(A[j+k+i],A[j+k]);
    			}
    		}
    	}
    }
    
    inline void FWT_and(int *A,bool opt=1){
    	for(int i=1;i<len;i<<=1){
    		for(int j=0;j<len;j+=i<<1){
    			for(int k=0;k<i;++k){
    				A[j+k]=opt?add(A[j+k],A[j+k+i]):sub(A[j+k],A[j+k+i]);
    			}
    		}
    	}
    }
    
    // inline void FMT_or(int *A,int op(int,int)){
    // 	for(int i=1;i<len;i<<=1){
    // 		for(int j=0;j<=len;++j){
    // 			if(i&j)A[j]=op(A[j],A[j^i]);
    // 		}
    // 	}
    // }
    
    // inline void FMT_and(int *A,int op(int,int)){
    // 	for(int i=1;i<len;i<<=1){
    // 		for(int j=0;j<=len;++j){
    // 			if(i&j)A[j^i]=op(A[j^i],A[j]);
    // 		}
    // 	}
    // }
    
    inline void FWT_xor(int *A,bool opt=1){
    	for(int i=1;i<len;i<<=1){
    		for(int j=0;j<len;j+=i<<1){
    			for(int k=0;k<i;++k){
    				int u=A[j+k],v=A[j+k+i];
    				A[j+k]=add(u,v);
    				A[j+k+i]=sub(u,v);
    				if(!opt){
    					A[j+k]=(ll)A[j+k]*Inv2%p;
    					A[j+k+i]=(ll)A[j+k+i]*Inv2%p;
    				}
    			}
    		}
    	}
    }
    
    int cnt[N],A[N],B[N],C[N],F[N],fib[N],bit[N];
    int t[20][N],f[20][N];
    
    int main(){
    	int n;r(n);
    	for(int i=1,x;i<=n;++i){
    		r(x),++cnt[x];
    	}
    	for(int i=0;i<len;++i){
    		t[bit[i]=(bit[i>>1]+(i&1))][i]=cnt[i];
    	}
    	for(int i=0;i<=17;++i){
    		FWT_or(t[i]);
    		// FMT_or(t[i],add);
    	}
    	for(int i=0;i<=17;++i){
    		for(int j=0;i+j<=17;++j){
    			for(int k=0;k<len;++k){
    				f[i+j][k]=add(f[i+j][k],(ll)t[i][k]*t[j][k]%p);
    			}
    		}
    	}
    	for(int i=0;i<=17;++i)FWT_or(f[i],0);
    	// for(int i=0;i<=17;++i)FMT_or(f[i],sub);
    	for(int i=0;i<len;++i){
    		A[i]=f[bit[i]][i];
    	}
    	for(int i=0;i<len;++i){
    		B[i]=cnt[i];
    	}
    	FWT_xor(cnt);
    	for(int i=0;i<len;++i){
    		C[i]=(ll)cnt[i]*cnt[i]%p;
    	}
    	FWT_xor(C,0);
    	fib[1]=1;
    	for(int i=2;i<len;++i){
    		fib[i]=add(fib[i-1],fib[i-2]);
    	}
    	for(int i=0;i<len;++i){
    		A[i]=(ll)A[i]*fib[i]%p;
    		B[i]=(ll)B[i]*fib[i]%p;
    		C[i]=(ll)C[i]*fib[i]%p;
    	}
    	FWT_and(A);
    	FWT_and(B);
    	FWT_and(C);
    	// FMT_and(A,add);
    	// FMT_and(B,add);
    	// FMT_and(C,add);
    	for(int i=0;i<len;++i){
    		F[i]=(ll)A[i]*B[i]%p*C[i]%p;
    	}
    	FWT_and(F,0);
    	// FMT_and(F,sub);
    	int ans=0;
    	for(int i=1;i<len;i<<=1){
    		ans=add(ans,F[i]);
    	}
    	printf("%d
    ",ans);
    }
    
    
  • 相关阅读:
    cf1108E2 线段树类似扫描线
    poj1185 状态压缩经典题
    cf1110F 离线+树上操作+线段树区间更新
    tarjan求lca :并查集+dfs
    cf1110E 思维
    cf1110d 线性dp
    cf842D 01字典树|线段树 模板见hdu4825
    cf842C 树形dp+gcd函数
    cf581F 依赖背包+临时数组 好题
    hdu5758 思维,树形dp
  • 原文地址:https://www.cnblogs.com/yicongli/p/10190613.html
Copyright © 2011-2022 走看看