题解: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}\)

最终选数的方案数为:

\[sum= \frac{(\sum_{S} f_{0,S} )-(A+1) \times (B+1)}{2 \times 2} \]

除以 \(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;
}
posted @ 2025-03-18 10:42  wanggk  阅读(102)  评论(0)    收藏  举报