注意到一个数组内的数的种类不可能大于 222,于是大力分类讨论。
-
a,ba,ba,b 数组内的数均只有一种,此时生成的异或矩阵只有一种取值,满足题目条件,方案数为 (A+1)(B+1)(A + 1)(B + 1)(A+1)(B+1)。
-
aaa 数组内的数有两种,bbb 中只有一种。此时生成的异或矩阵有两种取值,仍然满足题目条件。可以给 aaa 数组内的数任意选择两种,并枚举其中一种数的个数。用二项式定理进一步化简,最终可得到方案数为
(B+1)×(A+12)∑i=1n−1(ni)=12(B+1)(A+1)A∑i=1n−1(ni)=12(B+1)(A+1)A(2n−2) (B + 1) \times \binom {A + 1}{2} \sum \limits_{i = 1}^{n - 1} \binom {n}{i} \\ =\dfrac{1}{2}{(B + 1)(A + 1)A}\sum \limits_{i = 1}^{n - 1} \binom {n}{i} \\ =\dfrac{1}{2}{(B + 1)(A + 1)A}(2^n - 2) (B+1)×(2A+1)i=1∑n−1(in)=21(B+1)(A+1)Ai=1∑n−1(in)=21(B+1)(A+1)A(2n−2)
- bbb 数组内的数有两种,aaa 中只有一种。同理可得方案数为
12(A+1)(B+1)B(2m−2) \dfrac{1}{2}{(A + 1)(B + 1)B}(2^m - 2) 21(A+1)(B+1)B(2m−2)
- a,ba,ba,b 数组内的数均有两种。设 aaa 中存在 x1,x2 (x1≠x2)x_1,x_2\ (x_1 \neq x_2)x1,x2 (x1=x2),bbb 中存在 y1,y2 (y1≠y2)y_1,y_2\ (y_1 \neq y_2)y1,y2 (y1=y2),则只有 x1⊕y2=x2⊕y1x_1 \oplus y_2 = x_2 \oplus y_1x1⊕y2=x2⊕y1 时满足题意。交换一下可得 x1⊕x2=y1⊕y2x_1 \oplus x_2 = y_1 \oplus y_2x1⊕x2=y1⊕y2。由于每一位相互独立,所以设 dpi,0/1,0/1,0/1,0/1dp_{i,0/1,0/1,0/1,0/1}dpi,0/1,0/1,0/1,0/1 表示考虑到第 iii 位时,x1,x2,y1,y2x_1,x_2,y_1,y_2x1,x2,y1,y2 是否已经达到上界时的方案数,直接大力数位 dp 即可。需要注意的时,最后还需要枚举某一个数的个数,也就是乘上
∑i=1n−1(ni)×∑i=1m−1(mi)=(2n−2)(2m−2) \sum \limits_{i = 1}^{n - 1} \binom {n}{i} \times \sum \limits_{i = 1}^{m - 1} \binom {m}{i} \\ = (2^n - 2)(2^m - 2) i=1∑n−1(in)×i=1∑m−1(im)=(2n−2)(2m−2)
最终代码如下:
#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;
}