- 给定一个长度为(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的幂的部分求和
}