CodeForces914G Sum the Fibonacci
这是一道FWT
好题!
虽然更多的人应该觉得这是个简单套路题
但是正因为经典才能成为套路不是吗?
用FWT
统计方案数
设\(cnt[i]\)表示\(S_x=i\)的方案数
\(A[i]\)表示\(S_a|S_b=i\)且\(S_a \& S_b=0\)的方案数
B[i]表示\(S_a=i\)的方案数(就是\(cnt[i ]\))
\(C[i]\)表示\(S_a \oplus S_b=i\)
算出方案数再乘上对应的斐波那契数
最后再与卷积
统计\(2^i\)的答案即可
话说我发现FWT
跑得比FMT
快
\(170\)个测试点差了\(4s\)
#include<bits/stdc++.h>
using namespace std;
#define gc c=getchar()
#define r(x) read(x)
#define ll long long
template<typename T>
inline void read(T&x){
x=0;T k=1;char gc;
while(!isdigit(c)){if(c=='-')k=-1;gc;}
while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
}
const int len=1<<17;
const int N=len|7;
const int p=1e9+7;
const int Inv2=(p+1)>>1;
inline int add(int a,int b){
a+=b;
if(a>=p)a-=p;
return a;
}
inline int sub(int a,int b){
a-=b;
if(a<0)a+=p;
return a;
}
inline void FWT_or(int *A,bool opt=1){
for(int i=1;i<len;i<<=1){
for(int j=0;j<len;j+=i<<1){
for(int k=0;k<i;++k){
A[j+k+i]=opt?add(A[j+k],A[j+k+i]):sub(A[j+k+i],A[j+k]);
}
}
}
}
inline void FWT_and(int *A,bool opt=1){
for(int i=1;i<len;i<<=1){
for(int j=0;j<len;j+=i<<1){
for(int k=0;k<i;++k){
A[j+k]=opt?add(A[j+k],A[j+k+i]):sub(A[j+k],A[j+k+i]);
}
}
}
}
// inline void FMT_or(int *A,int op(int,int)){
// for(int i=1;i<len;i<<=1){
// for(int j=0;j<=len;++j){
// if(i&j)A[j]=op(A[j],A[j^i]);
// }
// }
// }
// inline void FMT_and(int *A,int op(int,int)){
// for(int i=1;i<len;i<<=1){
// for(int j=0;j<=len;++j){
// if(i&j)A[j^i]=op(A[j^i],A[j]);
// }
// }
// }
inline void FWT_xor(int *A,bool opt=1){
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 u=A[j+k],v=A[j+k+i];
A[j+k]=add(u,v);
A[j+k+i]=sub(u,v);
if(!opt){
A[j+k]=(ll)A[j+k]*Inv2%p;
A[j+k+i]=(ll)A[j+k+i]*Inv2%p;
}
}
}
}
}
int cnt[N],A[N],B[N],C[N],F[N],fib[N],bit[N];
int t[20][N],f[20][N];
int main(){
int n;r(n);
for(int i=1,x;i<=n;++i){
r(x),++cnt[x];
}
for(int i=0;i<len;++i){
t[bit[i]=(bit[i>>1]+(i&1))][i]=cnt[i];
}
for(int i=0;i<=17;++i){
FWT_or(t[i]);
// FMT_or(t[i],add);
}
for(int i=0;i<=17;++i){
for(int j=0;i+j<=17;++j){
for(int k=0;k<len;++k){
f[i+j][k]=add(f[i+j][k],(ll)t[i][k]*t[j][k]%p);
}
}
}
for(int i=0;i<=17;++i)FWT_or(f[i],0);
// for(int i=0;i<=17;++i)FMT_or(f[i],sub);
for(int i=0;i<len;++i){
A[i]=f[bit[i]][i];
}
for(int i=0;i<len;++i){
B[i]=cnt[i];
}
FWT_xor(cnt);
for(int i=0;i<len;++i){
C[i]=(ll)cnt[i]*cnt[i]%p;
}
FWT_xor(C,0);
fib[1]=1;
for(int i=2;i<len;++i){
fib[i]=add(fib[i-1],fib[i-2]);
}
for(int i=0;i<len;++i){
A[i]=(ll)A[i]*fib[i]%p;
B[i]=(ll)B[i]*fib[i]%p;
C[i]=(ll)C[i]*fib[i]%p;
}
FWT_and(A);
FWT_and(B);
FWT_and(C);
// FMT_and(A,add);
// FMT_and(B,add);
// FMT_and(C,add);
for(int i=0;i<len;++i){
F[i]=(ll)A[i]*B[i]%p*C[i]%p;
}
FWT_and(F,0);
// FMT_and(F,sub);
int ans=0;
for(int i=1;i<len;i<<=1){
ans=add(ans,F[i]);
}
printf("%d\n",ans);
}