题解:CF2075E XOR Matrix

注意到一个数组内的数的种类不可能大于 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=1n1(in)=21(B+1)(A+1)Ai=1n1(in)=21(B+1)(A+1)A(2n2)

  • 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(2m2)

  • 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_1x1y2=x2y1 时满足题意。交换一下可得 x1⊕x2=y1⊕y2x_1 \oplus x_2 = y_1 \oplus y_2x1x2=y1y2。由于每一位相互独立,所以设 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=1n1(in)×i=1m1(im)=(2n2)(2m2)

最终代码如下:

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值