【CF914G】Sum the Fibonacci(FWT)

点此看题面

  • 给定一个长度为(n)的序列(s_i)
  • 定义一个五元组((a,b,c,d,e))合法,当且仅当(1le a,b,c,d,ele n)((s_a|s_b)&s_c&(s_doplus s_e))(2)的幂,(s_a&s_b=0)
  • 对于所有合法的五元组((a,b,c,d,e)),求(sum Fib(s_a|s_b) imes Fib(s_c) imes Fib(s_doplus s_e))
  • (nle10^6,0le 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_doplus 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
",t),0;//取下标为2的幂的部分求和
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF914G.html