不会 FWT 的真实。需要重写篇 FWT 博客。
考虑 Takahashi 获胜当且仅当 Aoki 和 Snuke 选的相同,Takahashi 选的是它的下一个。
至少有一个相等,可以容斥为所有的都不相等。
那么相当于两个数能够给一个集合造成贡献。比如 \(R, R \to \{R, S\}\),\(R, P \to \{R, P, S\}\)。
发现只有四种集合,我们就可以将这四种集合定一个 \([0, 3]\) 的数,然后考虑构造一个位运算。
容易得出 \(a \oplus b = \begin{cases}a & a=b\\3&a\ne b\end{cases}\)。
需要满足 \(c_0, c_1, c_2 \in \{0, 1\},\ c_0 c_1 = c_0 c_2 = c_1 c_2 = c_3\),那么有 \([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1]\) 四组解。
可以构造出 FWT 的转移矩阵 \(\begin{bmatrix}1 & 0 & 0 & 1\\0 & 1 & 0 & 1\\0 & 0 & 1 & 1\\0 & 0 & 0 & 1\end{bmatrix}\),其逆矩阵 \(\begin{bmatrix}1 & 0 & 0 & -1\\0 & 1 & 0 & -1\\0 & 0 & 1 & -1\\0 & 0 & 0 & 1\end{bmatrix}\)。实际上就是对于 \(3\) 这一位做了前缀和。
最后由于一位是对一个集合贡献,再类似于 FWT 转移一遍即可。
复杂度 \(O(k 4^k)\)。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 18000005;
long long a[MAXN], b[MAXN], c[MAXN];
int k, n, x, y;
char s[123];
int mp[255];
void fwt(long long *t) {
for (int mid = 1; mid < n; mid <<= 2)
for (int l = 0; l < n; l += (mid << 2))
for (int i = 0; i < mid; i++)
t[l + i + 3 * mid] += t[l + i] + t[l + i + mid] + t[l + i + 2 * mid];
}
void ifwt(long long *t) {
for (int mid = 1; mid < n; mid <<= 2)
for (int l = 0; l < n; l += (mid << 2))
for (int i = 0; i < mid; i++)
t[l + i + 3 * mid] -= t[l + i] + t[l + i + mid] + t[l + i + 2 * mid];
}
int main() {
scanf("%d%d%d", &k, &x, &y);
n = 1 << (2 * k);
mp['P'] = 0, mp['R'] = 1, mp['S'] = 2;
for (int i = 1; i <= x; i++) {
scanf("%s", s); int v = 0;
for (int j = 0; j < k; j++) v |= mp[s[j]] << (2 * j);
a[v] = 1;
}
for (int i = 1; i <= y; i++) {
scanf("%s", s); int v = 0;
for (int j = 0; j < k; j++) v |= mp[s[j]] << (2 * j);
b[v] = 1;
}
fwt(a), fwt(b);
for (int i = 0; i < n; i++) c[i] = a[i] * b[i];
ifwt(c);
for (int mid = 1; mid < n; mid <<= 2)
for (int l = 0; l < n; l += (mid << 2))
for (int i = 0; i < mid; i++) {
long long A = c[l + i], B = c[l + i + mid], C = c[l + i + 2 * mid], D = c[l + i + 3 * mid];
c[l + i] = A + C + D;
c[l + i + mid] = A + B + D;
c[l + i + 2 * mid] = B + C + D;
c[l + i + 3 * mid] = 0;
}
for (int i = 0; i < n; i++) {
bool flag = true;
int rev = 0;
for (int j = 0; j < k; j++) {
flag &= (i >> (2 * j) & 3) < 3;
rev |= (i >> (2 * j) & 3) << ((k - j - 1) * 2);
}
if (flag) {
c[rev] = 1ll * x * y - c[rev];
printf("%lld\n", c[rev]);
}
}
return 0;
}
标签:ARC132F,int,long,Strongest,MAXN,bmatrix,FWT,Takahashi
From: https://www.cnblogs.com/apjifengc/p/17223024.html