题解:CF2075E XOR Matrix
题意
对于数组 \(a\) 和 \(b\) ,定义 \(n \times m\) 的矩阵 \(X_{i,j} = a_i \oplus b_j\)。
给你 \(n, m, A, B\),求出有多少数组对 \((a, b)\) 满足:
- \(a\) 长度为 \(n\) 且值域为 \([0,A]\)。
- \(b\) 长度为 \(m\) 且值域为 \([0,B]\)。
- 生成的矩阵中,不同的值不超过两个。
\(2 \le n, m, A, B \le 2^{29} - 1\)。
题解
可以发现同一个数,异或上不同的两个数,结果一定不同。因此,数组 \(a,b\) 均满足:不同的值的个数不超过 \(2\)。
分类讨论,对 \(a,b\) 中不同的值的个数为 \(1\) 或 \(2\) 分别讨论。
情况一:\(a,b\) 数组均只有一个值
方案数为 \((A+1) \times (B+1)\)。
情况二:一个数组有两个不同值,另一个只有一个值
- \(a\) 数组只有一个值:\(A \times C_{B+1}^2 \times Calc_m\)。
- 反过来,\(b\) 数组只有一个值:\(B \times C_{A+1}^2 \times Calc_n\)。
其中,\(Calc_m\) 表示,用两个不同数(每种数都要用),填满数组的 \(m\) 个位置的方案数,即 \(Calc_m=2^m-2\)。
情况三:\(a,b\) 数组均有两个不同值
设 \(a\) 数组的值为 \(x,y(x \not = y)\),\(b\) 数组的值为 \(p,q(p \not = q)\)。
矩阵中所有的可能值为 \(x \oplus p,x \oplus q,y \oplus p,y \oplus q\),因为 \(x \not = y,p \not =q\),所以只可能 \(x \oplus p = y \oplus q\),即 \(x \oplus y \oplus p \oplus q =0\)。
所以这一种情况转化为,统计以下四元组 \((x,y,p,q)\) 的个数(这一统计的答案记作 \(sum\)):
- \(x,y \in [0,A]\)。
- \(p,q \in [0,B]\)。
- \(x \oplus y \oplus p \oplus q =0\)。
- \(x \not = y,p \not = q\)。
显然,当 \(x=y,p=q\) 时一定满足第三个条件,所以我们只需要先忽略最后一个条件,再减去 \(x=y,p=q\) 时的 \((A+1) \times (B+1)\) 即可。
忽略最后一个条件后就是一个二进制下的数位 DP 了。设 \(f_{k,0/1,0/1,0/1,0/1}\) 表示,已经填完了二进制下前 \(k\) 位,当前 \(x,y,p,q\) 是否达到 \(A\) 或 \(B\) 的上限,此时的方案数。
刷表法转移,设当前是 \(f_{k,S}\)(\(S\) 为那四个 \(01\) 的状压),用 \(2^{16}\) 枚举 \(x,y,p,q\) 的这一位分别填 \(0\) 还是 \(1\),检查是否合法(不超过这一位上界)并更新新的上界 \(to\),转移 \(f_{k-1,to} \leftarrow f_{k,S}\)。
最终选数的方案数为:
除以 \(4\) 是因为要除掉 \(x,y\) 的选择顺序和 \(p,q\) 的选择顺序。
算上安排位置的方案,情况三的答案就为 \(sum \times Calc_m \times Calc_n\)。
最后三种情况相加即可。
代码
完整代码见提交记录。
写了一部分注释:
void solve()
{
rd(n,m,A,B);
ans=(A+1ll)*(B+1ll)%mod;//情况一
qadd(ans,B*(B+1ll)/2ll%mod*(A+1ll)%mod*calc(m)%mod);//情况二
qadd(ans,A*(A+1ll)/2ll%mod*(B+1ll)%mod*calc(n)%mod);//情况二
if(m<2 || n<2 || !A || !B){
write(ans),End;
return;
}
//下面都是情况三
memset(f,0,sizeof(f));
For(i,0,29) up[i][0]=up[i][1]=(A>>i)&1,up[i][2]=up[i][3]=(B>>i)&1;//类似数位 DP,获取上界
f[30][0]=1ll;
Forr(k,30,1) For(lim,0,15) if(f[k][lim])
For(val,0,15) if(!ppc[val]) //val 是枚举 x,y,p,q 这一位填什么,因为要异或和为 0,所以每一位的异或(ppc[val])都要是 0
{
int to=lim;
bool flag=true;//flag=false 即不合法
For(i,0,3)
if(!(lim>>i&1)){ //0 表示对最高位有限制,1 表示对当前位无限制(可能和大多数人习惯反过来?)
if((val>>i&1)<up[k-1][i]) to|=(1<<i); //这位严格小于上界,那么此后无限制
else if((val>>i&1)>up[k-1][i]){
flag=false;
break;
}
}
if(flag) qadd(f[k-1][to],f[k][lim]);
}
ll sum=0;
For(lim,0,15) qadd(sum,f[0][lim]);
ll red=(A+1ll)*(B+1ll)%mod;
sum=(sum-red+mod)%mod;
sum=sum*inv2%mod*inv2%mod;
qadd(ans,sum*calc(n)%mod*calc(m)%mod);
write(ans),End;
}

浙公网安备 33010602011771号