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);
}

posted @ 2018-12-28 14:59  NamelessOIer  阅读(137)  评论(0编辑  收藏  举报