arc141 B - Increasing Prefix XOR

题意:

给定 \(n,m\),问有多少数组 \(a[]\) 满足:

  • \(1\le a_1< a_2 < \cdots < a_n \le m\)
  • \(b_1<b_2<\cdots <b_n\),其中 \(b[]\) 为前缀异或和即 \(b_i=a_1\oplus a_2\oplus \cdots \oplus a_i\)

\(1\le n \le m<2^{60}\)

思路:

\(a_i<a_{i+1}\)\(a_{i+1}\) 的位数不少于 \(a_i\) 的位数(位数指二进制位数)

\(b_i<b_{i+1}=b_i\oplus a_{i+1}\)\(a_{i+1}\) 的位数不等于 \(b_i\) 的位数

所以若 \(a_i\)\(b_i\) 有相同的位数,则 \(a_{i+1}\) 的位数严格大于 \(a_i\)\(b_i\) 的位数

\(a_1=b_1\implies a_1\)\(b_1\) 位数相同 \(\implies a_2\) 的位数严格大于 \(a_1,b_1\) 的位数 \(\implies b_2\) 的位数等于 \(a_2\) 的位数

以此类推得 \(a_i\) 的位数严格递增就行了!

因为 \(m<2^{60}\) 所以 \(m\) 最多有 60 位,所以当 \(n>60\) 时答案为 0

\(n\le 60\) 时 dp 一下:\(f(i,j)\) 表示 \(n=i\)\(a_i\)\(j\)

ll n, m, f[N][N], g[N]; //恰有i位的数有几个
void sol()
{
    cin >> n >> m;
    if (n > 60)
        return cout << 0, void();
    int dig = log2(m) + 1;

    g[dig] = m; //预处理g[]
    for (int i = 1; i < dig; i++)
        g[i] = qmi(2, i - 1), g[dig] = add(g[dig], -g[i]);

    f[0][0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = i; j <= dig; j++)    //当前位数
            for (int k = 0; k < j; k++) //上一个位数
                f[i][j] = add(f[i][j], mul(g[j], f[i - 1][k]));

    ll ans = 0;
    for (int i = 1; i <= dig; i++)
        ans = add(ans, f[n][i]);
    cout << ans;
}
posted @ 2022-06-07 13:54  Bellala  阅读(108)  评论(0)    收藏  举报