很奇妙,FMT 有趣题。
首先可以一眼(或两眼)看出(或推出)式子:
这好像是个卷积,FFT???然后就想歪了。
根据 Lucas 定理,我们有
我们发现当且仅当
深思一番后,发现这相当于
t
t
二进制位构成的集合属于 二进制位构成的集合,即
t⊆x
t
⊆
x
,假装 t,x 是集合。
式子等价于:
这就是一个 FMT 了,如果直接上的话,
O(log2n2logn)
O
(
log
n
2
2
log
n
)
,
因为只需要知道奇偶性,所以加个 bitset 优化,则可以做到
O(logn2logn)
O
(
log
n
2
log
n
)
。
#include <cstdio>
#include <cstring>
#include <bitset>
int n, m;
char r[1 << 20 | 15], b[1 << 20 | 15];
int f[1 << 21], R[1 << 21], B[1 << 21];
std::bitset<1 << 21> ft[21], Rt[21], Bt[21];
int main()
{
scanf("%d %d", &n, &m);
scanf("%s %s", r + 1, b + 1);
for(int i = 1; i <= n; ++i) (r[i] -= '0') &= 1; r[0] = 1;
for(int i = 1; i <= m; ++i) (b[i] -= '0') &= 1; b[0] = 1;
for(int i = 0; i <= n; ++i) if(r[i])
{
int cnt = 0;
for(int j = 0; j < 21; ++j) cnt += i >> j & 1;
R[i] = 1 << cnt;
}
for(int i = 0; i <= m; ++i) if(b[i])
{
int cnt = 0;
for(int j = 0; j < 21; ++j) cnt += i >> j & 1;
B[i] = 1 << cnt;
}
for(int i = 0; i < 21; ++i)
for(int j = 0; j < (1 << 21); ++j) if(!(j >> i & 1))
{
R[j | 1 << i] ^= R[j];
B[j | 1 << i] ^= B[j];
}
for(int i = 0; i < (1 << 21); ++i)
for(int j = 0; j < 21; ++j)
{
if(R[i] >> j & 1) Rt[j][i] = 1;
if(B[i] >> j & 1) Bt[j][i] = 1;
}
for(int k = 0; k < 21; ++k)
for(int d = 0; d <= k; ++d)
ft[k] = ft[k] ^ (Rt[d] & Bt[k - d]);
for(int i = 0; i < 21; ++i)
for(int j = 0; j < (1 << 21); ++j) if(ft[i][j])
f[j] |= 1 << i;
for(int i = 0; i < 21; ++i)
for(int j = 0; j < (1 << 21); ++j) if(!(j >> i & 1))
f[j | 1 << i] ^= f[j];
long long Ans = 0;
for(int i = 1; i <= n + m; ++i)
{
int cnt = 0;
for(int j = 0; j < 21; ++j) cnt += i >> j & 1;
if(f[i] >> cnt & 1) Ans += 1ll * i * i;
}
printf("%lld\n", Ans);
return 0;
}