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\n",ans);
}

posted @ 2020-05-27 15:45  Izayoi_Doyo  阅读(141)  评论(0编辑  收藏  举报