注意到一个数组内的数的种类不可能大于 $2$,于是大力分类讨论。

  • $a,b$ 数组内的数均只有一种,此时生成的异或矩阵只有一种取值,满足题目条件,方案数为 $(A + 1)(B + 1)$。

  • $a$ 数组内的数有两种,$b$ 中只有一种。此时生成的异或矩阵有两种取值,仍然满足题目条件。可以给 $a$ 数组内的数任意选择两种,并枚举其中一种数的个数。用二项式定理进一步化简,最终可得到方案数为

  • $b$ 数组内的数有两种,$a$ 中只有一种。同理可得方案数为
  • $a,b$ 数组内的数均有两种。设 $a$ 中存在 $x_1,x_2 (x_1 \neq x_2)$,$b$ 中存在 $y_1,y_2 (y_1 \neq y_2)$,则只有 $x_1 \oplus y_2 = x_2 \oplus y_1$ 时满足题意。交换一下可得 $x_1 \oplus x_2 = y_1 \oplus y_2$。由于每一位相互独立,所以设 $dp_{i,0/1,0/1,0/1,0/1}$ 表示考虑到第 $i$ 位时,$x_1,x_2,y_1,y_2$ 是否已经达到上界时的方案数,直接大力数位 dp 即可。需要注意的时,最后还需要枚举某一个数的个数,也就是乘上

最终代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h>
#define init(x) memset (x,-1,sizeof (x))
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define pii pair <int,int>
using namespace std;
const int MAX = 1e5 + 5;
const int MOD = 998244353;
inline int read ();
int t,a[35],b[35];ll n,m,A,B,ans,inv_2 = 499122177,dp[35][2][2][2][2];
ll qpow (ll x,ll y)
{
ll res = 1;
while (y)
{
if (y & 1) res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
int dfs (int x,bool lead,bool p1,bool p2,bool p3,bool p4)
{
if (x >= 30) return !lead;//不能均为 0
if (~dp[x][p1][p2][p3][p4]) return dp[x][p1][p2][p3][p4];
ll sum = 0;
for (int d1 = 0;d1 <= (p1 ? a[x] : 1);++d1)
for (int d2 = 0;d2 <= (p2 ? d1 : 1);++d2)
for (int d3 = 0;d3 <= (p3 ? b[x] : 1);++d3)
for (int d4 = 0;d4 <= (p4 ? d3 : 1);++d4)
if ((d1 ^ d2) == (d3 ^ d4))
sum += dfs (x + 1,lead && !(d1 ^ d2),p1 && (d1 == a[x]),p2 && (d2 == d1),p3 && (d3 == b[x]),p4 && (d4 == d3)),sum %= MOD;
return dp[x][p1][p2][p3][p4] = sum;
}
int main ()
{
//freopen (".in","r",stdin);
//freopen (".out","w",stdout);
t = read ();
while (t--)
{
n = read ();m = read ();A = read ();B = read ();
ans = (A + 1) * (B + 1) % MOD;
ans += (A + 1) * (B + 1) % MOD * B % MOD * inv_2 % MOD * (qpow (2,m) - 2 + MOD) % MOD;ans %= MOD;
ans += (B + 1) * (A + 1) % MOD * A % MOD * inv_2 % MOD * (qpow (2,n) - 2 + MOD);ans %= MOD;
for (int i = 0;i < 30;++i,A >>= 1) a[29 - i] = A & 1;
for (int i = 0;i < 30;++i,B >>= 1) b[29 - i] = B & 1;
init (dp);
ans += dfs (0,1,1,1,1,1) * (qpow (2,m) - 2 + MOD) % MOD * (qpow (2,n) - 2 + MOD) % MOD;ans %= MOD;
printf ("%lld\n",ans);
}
return 0;
}
inline int read ()
{
int s = 0;int f = 1;
char ch = getchar ();
while ((ch < '0' || ch > '9') && ch != EOF)
{
if (ch == '-') f = -1;
ch = getchar ();
}
while (ch >= '0' && ch <= '9')
{
s = s * 10 + ch - '0';
ch = getchar ();
}
return s * f;
}