把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF914G】Sum the Fibonacci(FWT)

点此看题面

  • 给定一个长度为\(n\)的序列\(s_i\)
  • 定义一个五元组\((a,b,c,d,e)\)合法,当且仅当\(1\le a,b,c,d,e\le n\)\((s_a|s_b)\&s_c\&(s_d\oplus s_e)\)\(2\)的幂,\(s_a\&s_b=0\)
  • 对于所有合法的五元组\((a,b,c,d,e)\),求\(\sum Fib(s_a|s_b)\times Fib(s_c)\times Fib(s_d\oplus s_e)\)
  • \(n\le10^6,0\le s_i<2^{17}\)

\(FWT\)裸题

首先求出\(f1_i,f2_i,f3_i\)分别表示选出\(s_a\&s_b=0\)\(s_a|s_b=i\)\(s_c=i\)\(s_d\oplus s_e=i\)的方案数。

对于\(f1_i\),这相当于是一个子集卷积,只需再开一维记录\(1\)的个数简单相加应该是多少,则\(s_a\&s_b=0\)的时候就需要满足实际或运算得到的\(1\)的个数与其相等。

对于\(f2_i\),这就是普通的计数数组。

对于\(f3_i\),这相当于是一个裸的异或卷积。

然后我们把\(f1_i,f2_i,f3_i\)都乘上\(Fib_i\),最后再对它们做一个与卷积,选出下标是\(2\)的幂的部分求和即可得出答案。

代码:\(O(slogs)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define P 131072
#define L 17
#define X 1000000007
#define I2 500000004
using namespace std;
int n,a[N+5],f[P],f1[P],f2[P],f3[P],Fib[P];
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	char oc,FI[FS],*FA=FI,*FB=FI;
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
namespace Or//第一部分,子集卷积
{
	int c[P],f[L+1][P],g[L+1][P];
	I void FWT_Or(int* s,CI op)
	{
		RI i,j,k;for(i=1;i^P;i<<=1) for(j=0;j^P;j+=i<<1) for(k=0;k^i;++k) s[i+j+k]=(s[i+j+k]+1LL*op*s[j+k])%X;
	}
	I void Solve()
	{
		RI i,j,k;for(i=1;i^P;++i) c[i]=c[i>>1]+(i&1);for(i=1;i<=n;++i) ++f[c[a[i]]][a[i]];
		for(i=0;i<=L;++i) FWT_Or(f[i],1);//内层FWT
		for(i=0;i^P;++i) for(j=L;~j;--j) for(k=L-j;~k;--k) g[j+k][i]=(g[j+k][i]+1LL*f[j][i]*f[k][i])%X;//外层暴力卷积
		for(i=0;i<=L;++i) FWT_Or(g[i],X-1);for(i=0;i^P;++i) f1[i]=g[c[i]][i];//IFWT回去,或运算结果1的个数应与简单相加时相等
	}
}
namespace None//第二部分,就是计数数组
{
	I void Solve()
	{
		for(RI i=1;i<=n;++i) ++f2[a[i]];
	}
}
namespace Xor//第三部分,异或卷积
{
	I void FWT_Xor(int* s,CI op)
	{
		RI i,j,k,x,y;for(i=1;i^P;i<<=1) for(j=0;j^P;j+=i<<1) for(k=0;k^i;++k)
			s[j+k]=((x=s[j+k])+(y=s[i+j+k]))%X,s[i+j+k]=(x-y+X)%X,!~op&&(s[j+k]=1LL*s[j+k]*I2%X,s[i+j+k]=1LL*s[i+j+k]*I2%X);
	}
	I void Solve()
	{
		RI i;for(i=1;i<=n;++i) ++f3[a[i]];for(FWT_Xor(f3,1),i=0;i^P;++i) f3[i]=1LL*f3[i]*f3[i]%X;FWT_Xor(f3,-1);//自乘
	}
}
namespace And//最终结果,与卷积
{
	I void FWT_And(int* s,CI op)
	{
		RI i,j,k;for(i=1;i^P;i<<=1) for(j=0;j^P;j+=i<<1) for(k=0;k^i;++k) s[j+k]=(s[j+k]+1LL*op*s[i+j+k])%X;
	}
	I void Solve()
	{
		RI i;for(i=0;i^P;++i) f1[i]=1LL*f1[i]*Fib[i]%X,f2[i]=1LL*f2[i]*Fib[i]%X,f3[i]=1LL*f3[i]*Fib[i]%X;//乘上权值(Fib[i])
		for(FWT_And(f1,1),FWT_And(f2,1),FWT_And(f3,1),i=0;i^P;++i) f[i]=1LL*f1[i]*f2[i]%X*f3[i]%X;FWT_And(f,X-1);//三个卷在一起
	}
}
int main()
{
	RI i;for(Fib[1]=1,i=2;i^P;++i) Fib[i]=(Fib[i-1]+Fib[i-2])%X;for(read(n),i=1;i<=n;++i) read(a[i]);
	RI t=0;for(Or::Solve(),None::Solve(),Xor::Solve(),And::Solve(),i=1;i^P;i<<=1) t=(t+f[i])%X;return printf("%d\n",t),0;//取下标为2的幂的部分求和
}
posted @ 2021-05-17 13:43  TheLostWeak  阅读(35)  评论(0编辑  收藏  举报