• CF914G Sum the Fibonacci


    题目传送门

    分析:
    良心CF不卡(O(3^n))(错乱
    (s_a)(s_b)组合我们看做两个不相交集合合并成一个集合作贡献
    (s_d)(s_e)就是裸的异或卷积
    中间三个就是与卷积了
    第一个目前我们只会(O(3^n)),于是引入子集卷积
    最初的式子为:

    (F[i]=sum_{j|k=i}~[j&k=0]F[j]F[k])

    (sz[i])表示(i)在二进制状态下(1)的个数
    我们在每一个&F[i]&前加一位变成(F[sz[i]][i])

    (F[sz[i]][i]=sum_{j|k=i,sz[j]+sz[k]=sz[i]}~~~F[sz[j]][j]F[sz[k]][k])

    这样做或卷积就没有问题了
    复杂度是(O(2^nn^2)),可以做(n geq 18)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    
    #define maxn 1000005
    #define INF 0x3f3f3f3f
    #define MOD 1000000007
    #define inv2 500000004
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,len=1<<17,ans;
    int a[maxn],b[maxn],c[maxn],d[18][maxn],e[18][maxn],f[maxn],cnt[maxn],s[maxn];
    inline int upd(int x){return x<MOD?x:x-MOD;}
    
    inline void FWT_and(int *a,int len,int op)
    {
    	for(int i=1;i<len;i<<=1)for(int j=0;j<len;j+=(i<<1))for(int k=0;k<i;k++)
    		if(~op)a[j+k]=upd(a[j+k]+a[i+j+k]);
    		else a[j+k]=upd(a[j+k]+MOD-a[i+j+k]);
    }
    
    inline void FWT_or(int *a,int len,int op)
    {
    	for(int i=1;i<len;i<<=1)for(int j=0;j<len;j+=(i<<1))for(int k=0;k<i;k++)
    		if(~op)a[i+j+k]=upd(a[j+k]+a[i+j+k]);
    		else a[i+j+k]=upd(a[i+j+k]+MOD-a[j+k]);
    }
    
    inline void FWT_xor(int *a,int len,int op)
    {
    	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 x=a[j+k],y=a[i+j+k];
    		a[j+k]=upd(x+y),a[i+j+k]=upd(x+MOD-y);
    		if(!~op)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
    	}
    }
    
    int main()
    {
    	n=getint();
    	for(int i=1;i<=n;i++)s[getint()]++;
    	for(int i=1;i<len;i++)cnt[i]=cnt[i>>1]+(i&1);
    	f[1]=1;
    	for(int i=2;i<len;i++)f[i]=upd(f[i-1]+f[i-2]);
    	for(int i=0;i<len;i++)d[cnt[i]][i]=s[i];
    	for(int i=0;i<=17;i++)FWT_or(d[i],len,1);
    	for(int i=0;i<=17;i++)for(int j=0;j<=i;j++)for(int k=0;k<len;k++)
    		e[i][k]=upd(e[i][k]+1ll*d[j][k]*d[i-j][k]%MOD);
    	for(int i=0;i<=17;i++)FWT_or(e[i],len,-1);
    	for(int i=0;i<len;i++)a[i]=1ll*f[i]*e[cnt[i]][i]%MOD;
    	for(int i=0;i<len;i++)b[i]=1ll*s[i]*f[i]%MOD;
    	FWT_xor(s,len,1);
    	for(int i=0;i<len;i++)c[i]=1ll*s[i]*s[i]%MOD;
    	FWT_xor(c,len,-1);
    	for(int i=0;i<len;i++)c[i]=1ll*c[i]*f[i]%MOD;
    	FWT_and(a,len,1),FWT_and(b,len,1),FWT_and(c,len,1);
    	for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%MOD*c[i]%MOD;
    	FWT_and(a,len,-1);
    	for(int i=0;i<17;i++)ans=upd(ans+a[1<<i]);
    	printf("%d
    ",ans);
    }
    

  • 相关阅读:
    【2020-05-03】发掘自己内心那个原点的力量
    【2020-05-02】要适应不确定性
    【2020-05-01】人生十三信条
    【一句日历】2020年5月
    【2020-04-30】每一句话,都是自我学习
    【2020-04-29】勤奋是一种享受
    【2020-04-28】自我观念强化的实践
    【2020-04-27】自我提升的里程碑
    【2020-04-26】还在温室里的自己
    家谱树(信息学奥赛一本通 1351)
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12973526.html
Copyright © 2020-2023  润新知