CF914G Sum the Fibonacci
https://www.luogu.com.cn/problem/CF914G
首先按照套路肯定是先记下每个数出现的次数
然后大力FWT+FST即可
code:
#include<bits/stdc++.h>
#define mod 1000000007
#define ll long long
using namespace std;
const int N = (1 << 17) + 5;
const ll inv2 = (1 + mod) / 2;
void fwtor(ll *a, int n, int o) {
for(int len = 2; len <= n; len <<= 1)
for(int j = 0; j < n; j += len)
for(int k = j; k < j + (len >> 1); k ++)
a[k + (len >> 1)] = (a[k + (len >> 1)] + o * a[k] + mod) % mod;
}
void fwtand(ll *a, int n, int o) {
for(int len = 2; len <= n; len <<= 1)
for(int j = 0; j < n; j += len)
for(int k = j; k < j + (len >> 1); k ++)
a[k] = (a[k] + o * a[k + (len >> 1)] + mod) % mod;
}
void fwtxor(ll *a, int n, int o) {
for(int len = 2; len <= n; len <<= 1)
for(int j = 0; j < n; j += len)
for(int k = j; k < j + (len >> 1); k ++) {
ll X = a[k], Y = a[k + (len >> 1)];
a[k] = (X + Y) % mod, a[k + (len >> 1)] = (X - Y + mod) % mod;
if(o == -1) a[k] = a[k] * inv2 % mod, a[k + (len >> 1)] = a[k + (len >> 1)] * inv2 % mod;
}
}
int n, fib[N], cnt[N];
ll f[19][N], a[N], b[N], c[N], ls[N];
void init() {
fib[1] = 1;
for(int i = 2; i < N; i ++) fib[i] = (fib[i - 1] + fib[i - 2]) % mod;
for(int i = 1; i < N; i ++) cnt[i] = cnt[i >> 1] + (i & 1);
}
void FST(int n) {
for(int i = 0; i <= 17; i ++) fwtor(f[i], n, 1);
for(int i = 0; i <= 17; i ++) {
for(int S = 0; S < n; S ++) ls[S] = 0;
for(int j = 0; j <= i; j ++)
for(int S = 0; S < n; S ++)
ls[S] = (ls[S] + f[j][S] * f[i - j][S] % mod) % mod;
fwtor(ls, n, -1);
for(int S = 0; S < n; S ++)
if(cnt[S] == i) a[S] = (a[S] + ls[S]) % mod;
}
}
int main() {
init();
scanf("%d", &n);
for(int i = 1, x; i <= n; i ++) {
scanf("%d", &x);
f[cnt[x]][x] ++, b[x] = (b[x] + fib[x]) % mod, c[x] ++;
}
int len = (1 << 17);
FST(len);
fwtxor(c, len, 1);
for(int i = 0; i < len; i ++) c[i] = c[i] * c[i] % mod;
fwtxor(c, len, -1);
for(int i = 0; i < len; i ++) a[i] = a[i] * fib[i] % mod, c[i] = c[i] * fib[i] % mod;
fwtand(a, len, 1), fwtand(b, len, 1), fwtand(c, len, 1);
for(int i = 0; i < len; i ++) a[i] = a[i] * b[i] % mod * c[i] % mod;
fwtand(a, len, -1);
ll ans = 0;
for(int i = 1; i < len; i <<= 1) ans = (ans + a[i]) % mod;
printf("%lld", ans);
return 0;
}