题面
Description
Give you two arrays \(A[0..2^m-1]\) and \(B[0..2^m-1]\).
Please calculate array \(C[0..2^m-1]\):
\[
C[k]=\sum_{i~and~j=k}A[i~xor~j]*B[i~or~j]
\]
You just need to print \(\sum_{i=0}^{2^m-1}C[i]*1526^i ~mod~998244353\)
\(m<=19\)
\(0\leq A[i],B[i]< 998244353\)
Input
There is only one test case.
The first line consists of one integer \(m\).
The second line consists of \(2^m\) integers \(A[0..2^m-1]\)
The third line consists of \(2^m\) integers \(B[0..2^m-1]\)
Output
Output only one integer means the answer.
Sample Input
2 1 2 3 4 5 6 7 8
Sample Output
568535691
题意
\[ C[k]=\sum_{i~and~j=k}A[i~xor~j]*B[i~or~j] \]
计算上式
题解
我在做这题的时候没太有思路,去搜了题解,有一篇题解感觉说的很好
https://www.cnblogs.com/Tiw-Air-OAO/p/10274225.html
这种题,推式子显然不是我这种非专业数学选手掌握的,那么怎样提高自己做出这种题目的概率呢?
打表大概是一个很好的办法,这篇题解里也是这样入手的
~ | (1) | (2) | (3) | (4) |
---|---|---|---|---|
i | 0 | 0 | 1 | 1 |
j | 0 | 1 | 0 | 1 |
i xor j | 0 | 1 | 1 | 0 |
i or j | 0 | 1 | 1 | 1 |
i and j | 0 | 0 | 0 | 1 |
我们令\(a = i~xor~ j,b=i~or~j, c=i~and~j\)
我们可以发现,显然,当异或值某一位为1的时候,或该位上必定为1,此时,i和j是该位上是可以有两种情况的,01或者10,而异或值为0,或值为1,和异或值为1,或值为0,i和j都是唯一确定的,也就是说我们可以根据异或值按位1的数量来判断i和j能够产生a和b的(i,j)数目,也就是\(2^{bit(a)}\),其中bit(a)表示a中1的数量
这样,我们一开始的时候,就把a(x)乘上\(2^{bit(a)}\),这样我们就可以不考虑原来的i和j而直接考虑a,b了
仔细观察,\(a \oplus b = c\)
但是这个是有条件的,上面也说了,异或某一位是1,或该位上必定是1,也就是说,\(a~and~b=a\),这个条件我们不好控制,但我们可以用之前的bit数组来控制,\(a~and~b=a \Leftrightarrow bit(b)-bit(a) = bit(c)\)
我们可以把a数组中bit(i)=k的数放在\(A[bit[i]][i]\),b同理,然后做fwt得到c[i-j],然后只保留c中\(C[bit[i]][i]\)的数即可。
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 998244353; const ll inv2 = (mod + 1) >> 1; void fwt_xor(ll a[], int len, int op) { for (int h = 2; h <= len; h <<= 1) { for (int j = 0; j < len; j += h) { for (int k = j; k < j + h / 2; k++) { ll u = a[k], t = a[k + h / 2]; a[k] = (u + t) % mod; a[k + h / 2] = (u - t + mod) % mod; if (op == -1) { a[k] = a[k] * inv2 % mod; a[k + h / 2] = a[k + h / 2] * inv2 % mod; } } } } } const ll N = 1 << 20; ll a[N], b[N]; int bit[N]; ll A[21][N], B[21][N]; ll C[21][N]; int main() { int m; scanf("%d", &m); int n = (1 << m); for (int i = 0; i < n; i++) { scanf("%lld", &a[i]); } for (int i = 0; i < n; i++) { scanf("%lld", &b[i]); } for (int i = 0; i < n; i++) { bit[i] = 0; int x = i; while (x) { if (x & 1) bit[i]++; x >>= 1; } } for (int i = 0; i < n; i++) { A[bit[i]][i] = a[i] * (1ll << bit[i]) % mod; B[bit[i]][i] = b[i]; } for (int i = 0; i <= m; i++) { fwt_xor(A[i], n, 1); fwt_xor(B[i], n, 1); } for (int i = 0; i <= m; i++) { for (int j = 0; j <= i; j++) { for (int k = 0; k < n; k++) { C[i - j][k] = (C[i - j][k] + A[j][k] * B[i][k] % mod) % mod; } } } for (int i = 0; i <= m; i++) { fwt_xor(C[i], n, -1); } ll now = 1; ll ans = 0; for (int i = 0; i < n; i++) { ans = (ans + C[bit[i]][i] * now % mod) % mod; now = now * 1526 % mod; } printf("%lld\n", ans); return 0; }
来源:https://www.cnblogs.com/artoriax/p/12241760.html