CF914G Sum the Fibonacci(FWT模板+子集卷积)

title

题目

solution

( s a ∣ s b ) & s c & ( s d ⊕ s e ) = 2 i , i ∈ Z ; s a & s b = 0 (s_a|s_b)\&s_c\&(s_d⊕s_e)=2^i,i∈Z;s_a\&s_b=0 (sasb)&sc&(sdse)=2i,iZ;sa&sb=0
i = s a ∣ s b , j = s c , d = s d ⊕ s e i=s_a|s_b,j=s_c,d=s_d⊕s_e i=sasb,j=sc,d=sdse

∑ x ∑ i & j & k = x f i b i ∗ f i b j ∗ f i b k ∗ ( ∑ s a ∣ s b = i , s a & s b = 0 1 ) ∗ ( ∑ s c = j 1 ) ∗ ( ∑ s d ⊕ s e = k 1 ) \sum_{x}\sum_{i\&j\&k=x}fib_i*fib_j*fib_k*(\sum_{s_a|s_b=i,s_a\&s_b=0}1)*(\sum_{s_c=j}1)*(\sum_{s_d⊕s_e=k}1) xi&j&k=xfibifibjfibk(sasb=i,sa&sb=01)(sc=j1)(sdse=k1)

f i = ( ∑ s a ∣ s b = i , s a & s b = 0 1 ) , g j = ( ∑ s c = j 1 ) , h k = ( ∑ s d ⊕ s e = k 1 ) f_i=(\sum_{s_a|s_b=i,s_a\&s_b=0}1),g_j=(\sum_{s_c=j}1),h_k=(\sum_{s_d⊕s_e=k}1) fi=(sasb=i,sa&sb=01),gj=(sc=j1),hk=(sdse=k1)
f f f就是子集卷积直接做; g g g不做操作; h h h就是常规的 F W T _ x o r FWT\_xor FWT_xor卷积
最后三个一起带着各自的斐波拉契权值,做个 F W T _ a n d FWT\_and FWT_and卷积即可

code

#include <cstdio>
#include <cstring>
#define mod 1000000007
#define int long long
#define maxn 1 << 18
int n, ret, inv = ( mod + 1 ) >> 1;
int f[maxn], g[maxn], h[maxn], tmp[maxn], ans[maxn], fib[maxn];
int dp[20][maxn];

void FWT_or( int *v, int opt ) {
    
    
	for( int i = 1;i < maxn;i <<= 1 )
		for( int j = 0;j < maxn;j += ( i << 1 ) )
			for( int k = 0;k < i;k ++ )
				v[j + k + i] = ( v[j + k + i] + v[j + k] * opt + mod ) % mod;
}

void FWT_and( int *v, int opt ) {
    
    
	for( int i = 1;i < maxn;i <<= 1 )	
		for( int j = 0;j < maxn;j += ( i << 1 ) )
			for( int k = 0;k < i;k ++ )
				v[j + k] = ( v[j + k] + v[j + k + i] * opt + mod ) % mod;;
}

void FWT_xor( int *v, int opt ) {
    
    
	for( int i = 1;i < maxn;i <<= 1 )
		for( int j = 0;j < maxn;j += ( i << 1 ) )
			for( int k = 0;k < i;k ++ ) {
    
    
				int x = v[j + k], y = v[j + k + i];
				v[j + k] = ( x + y ) % mod;
				v[j + k + i] = ( x - y + mod ) % mod;
				if( opt == -1 ) {
    
    
					v[j + k] = v[j + k] * inv % mod;
					v[j + k + i] = v[j + k + i] * inv % mod;
				}
			}
}

signed main() {
    
    
	scanf( "%lld", &n );
	for( int i = 1, x;i <= n;i ++ ) {
    
    
		scanf( "%lld", &x );
		f[x] ++, g[x] ++, h[x] ++;
	}
	fib[1] = 1;
	for( int i = 2;i < maxn;i ++ )
		fib[i] = ( fib[i - 1] + fib[i - 2] ) % mod;
	for( int i = 0;i < maxn;i ++ )
		dp[__builtin_popcount( i )][i] = f[i], f[i] = 0;
	n = 18;
	for( int i = 0;i < n;i ++ )
		FWT_or( dp[i], 1 );
	for( int i = 0;i < n;i ++ ) {
    
    
		memset( tmp, 0, sizeof( tmp ) );
		for( int j = 0;j <= i;j ++ )
			for( int k = 0;k < maxn;k ++ )
				tmp[k] = ( tmp[k] + dp[j][k] * dp[i - j][k] % mod ) % mod;
		FWT_or( tmp, -1 );
		for( int j = 0;j < maxn;j ++ )
			if( __builtin_popcount( j ) == i )
				f[j] = ( f[j] + tmp[j] ) % mod;
	}
	FWT_xor( h, 1 );
	for( int i = 0;i < maxn;i ++ )
		h[i] = h[i] * h[i] % mod;
	FWT_xor( h, -1 ); 
	for( int i = 0;i < maxn;i ++ )
		f[i] = f[i] * fib[i] % mod, g[i] = g[i] * fib[i] % mod, h[i] = h[i] * fib[i] % mod;
	FWT_and( f, 1 ), FWT_and( g, 1 ), FWT_and( h, 1 );
	for( int i = 0;i < maxn;i ++ )
		ans[i] = f[i] * g[i] % mod * h[i] % mod;
	FWT_and( ans, -1 );
	for( int i = 1;i < maxn;i <<= 1 )
		ret = ( ret + ans[i] ) % mod;
	printf( "%lld\n", ret );
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Emm_Titan/article/details/115216637
sum