「解题报告」HDU6358 Innocence

发布时间 2023-06-16 16:42:43作者: APJifengc

其实挺简单的,但是考场上状态太差没推出来,暴力还挂了。麻了。

首先看题:发现,这不是我们异或 FWT 的题吗,下次出题记得标明出处

容易发现,我们实际上要求的就是集合幂级数 \([x^k](x^l + x^{l + 1} + \cdots + x^{r - 1} + x^r)^n\)。考虑直接手动模拟 FWT。

\(F(l, r) = FWT(x^l + x^{l + 1} + \cdots + x^{r - 1} + x^r)\),那么由于 FWT 是线性运算,我们直接前缀和差分就可以求出 \(F(l, r)\) 即可。我们设 \(G(r) = \sum_{i=0}^{r-1} x^i\),那么 \(F(l, r) = G(r + 1) - G(l)\)。那么我们要解决两个问题:

  1. \(G(r)\) 怎么计算;
  2. \(IFWT(F(l, r)^n)\) 怎么计算。

首先考虑第一个问题:直接写出 FWT 的式子:\(b_i = \sum (-1)^{p(i \operatorname{\&} j)} a_j\)。那么 \(G(r)\) 就是:

\[G(r)_ i = \sum_{j=0}^{r-1} (-1)^{p(i \operatorname{\&} j)} \]

考虑将 \(r\) 按照二进制位拆开,这样原来的区间可以拆成若干个形如 \(\left[\left(\left\lfloor\dfrac{r}{2^i}\right\rfloor - 1\right) 2^i, \left\lfloor\dfrac{r}{2^i}\right\rfloor 2^i - 1\right]\) 的区间,对每一个区间进行考虑。

首先考虑 \(G(2^m)\),容易发现这时候相当于任意选定一个集合,\(i\) 和这个集合的交的奇偶性之和,写成式子就是:

\[G(2^m)_ i = 2^{m - p(i \operatorname{\&} (2^m - 1))} \sum_{j=0}^{p(i \operatorname{\&} (2^m - 1))} \binom{p(i \operatorname{\&} (2^m - 1))}{i} (-1)^i = 2^{m - p(i \operatorname{\&} (2^m - 1))} [p(i \operatorname{\&} (2^m - 1)) = 0] = 2^m [i \operatorname{\&} (2^m - 1) = 0] \]

即,当且仅当 \(i\)\(2^m\) 的倍数时有值,值为 \(2^m\)

那么考虑拆分成的区间,考虑从 \(G(2^i)\) 递推过来。发现,对于每一个 \(G(2^i)_ j\),实际上只需要再乘上一个 \((-1)^{p(\left\lfloor\frac{j \operatorname{\&} r}{2^i}\right\rfloor)}\) 即可。而由于 \(j\) 仅在 \(2^i | j\) 的地方有值,那么 \((-1)^{p(\left\lfloor\frac{j \operatorname{\&} r}{2^i}\right\rfloor)} = (-1)^{p(j \operatorname{\&} r) + \lfloor\frac{j}{2^i}\rfloor \operatorname{\&} 1}\),我们可以把 \((-1)^{p(j \operatorname{\&} r)}\) 提出来,那么剩下的部分其实就是交替 \(\pm 2^i\)

那么我们就知道了,\(G(r)\) 就是若干个形如 \(\{2^i, 0, \cdots, 0, -2^i, 0, \cdots, 0, \cdots\}\) 的序列加起来。简单画一下,发现我们只关心 \(2^i\)\(\mathrm{lowbit}\)\(r\) 在这一位以下的所有位都会造成贡献。而我们又能想到,除了最高位以外,其它的每一位 \(\lfloor\frac{j}{2^i}\rfloor\) 一定都是偶数,即一定都是正,而最高位一定是负数。所以我们可以得出,\(G(r)_ i\) 实际上等于 \(r \operatorname{\&} (\mathrm{lowbit}(i) - 1)\) 除去最高位的所有位减掉最高位,再乘上 \((-1)^{p(i \operatorname{\&} r)}\)。即:

\[G(r)_ i = (-1)^{p(r \operatorname{\&} i)} ((r \operatorname{\&} (\mathrm{lowbit}(i) - 1)) - (r \operatorname{\&} \mathrm{lowbit}(i))) \]

需要注意 \(G(r)_0 = r\),因为 \(\mathrm{lowbit}(0)\) 没有定义。

现在考虑第二个问题:如何计算 \(IFWT(F(l, r))\)

同样直接手拆式子,可以得到:

\[\begin{aligned} IFWT(F(l, r)^n)_k &= \frac{1}{2^m} \sum_i (-1)^{p(i \operatorname{\&} k)} a_i\\ &= \frac{1}{2^m} \left((r - l)^n + \sum_{i \ge 1} (-1)^{p(i \operatorname{\&} k)} \left( (-1)^{p(r \operatorname{\&} i)} f(r, \mathrm{lowbit}(i)) - (-1)^{p(l \operatorname{\&} i)} f(l, \mathrm{lowbit}(i))\right)^n\right)\\ &= \frac{1}{2^m} \left((r - l)^n + \sum_{i \ge 1} (-1)^{p(i \operatorname{\&} k)} \sum_{j=0}^{n} \binom{n}{j} (-1)^{(n - j) p(r \operatorname{\&} i) + jp(l \operatorname{\&} i)} (-1)^k f(r,\mathrm{lowbit}(i))^{n - j} f(l,\mathrm{lowbit}(i))^j\right)\\ &= \frac{1}{2^m} \left((r - l)^n + \sum_{i \ge 1} (-1)^{p(i \operatorname{\&} k) + n p(i \operatorname{\&} r)} \sum_{j=0}^{n} \binom{n}{j} (-1)^{j p((l \oplus r) \operatorname{\&} i)} (-1)^k f(r,\mathrm{lowbit}(i))^{n - j} f(l,\mathrm{lowbit}(i))^j\right)\\ \end{aligned} \]

首先前面一部分如果 \(n\) 为奇数就直接给 \(k\) 异或上一个 \(r\),那么现在就只管后面一部分了。后面一部分比较恶心的就是那个 \((-1)^{j p((l \oplus r) \operatorname{\&} i)}\),考虑直接枚举 \(j\) 的奇偶性,那么那一部分就也可以提取出来了。发现后面的式子与 \(\mathrm{lowbit}(i)\) 有关,那么我们直接枚举这个 \(\mathrm{lowbit(i)}\),那么这部分相当于一个常量了。后面的东西是一个形如 \(\sum \binom{n}{i} a^i b^{n - i} [i \text{ is even/odd}]\),这个东西可以通过给 \(b\) 加上一个 \(-1\),由 \(\frac{(a+b)^n \pm (a-b)^n}{2}\) 实现只保留奇数 / 偶数位置的值,然后后面那个东西就也可以 \(O(\log n)\) 求出来了。

然后考虑前面的东西,实际要求一个形如 \(\sum_{\mathrm{lowbit}(i) = 2^j} (-1)^{p(i \operatorname{\&} k)}\) 的东西。首先 \(\mathrm{lowbit}(i) = 2^j\) 的限制可以直接通过两边都除以 \(2^j\) 去掉,那么剩下的就是 \(2^{m - j - 1}(-1)^{\lfloor\frac{k}{2^{j}}\rfloor \operatorname{\&} 1}[\lfloor\frac{k}{2^{j+1}}\rfloor = 0]\)。推导略掉了,容易推出来。

那么把式子揉揉即可。不是很难写。总复杂度 \(O(Tq\log^2n)\)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 305, P = 1000000007;
int T;
int n, l, r, q;
int qpow(int a, int b) {
    a = (a % P + P) % P;
    int ans = 1;
    while (b) {
        if (b & 1) ans = 1ll * ans * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return ans;
}
const int INV2 = (P + 1) / 2;
int main() {
    freopen("jerry.in", "r", stdin);
    freopen("jerry.out", "w", stdout);
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d%d", &n, &l, &r, &q);
        r++;
        int m = 30;
        while (q--) {
            int k; scanf("%d", &k);
            if (n & 1) k ^= r;
            int ans = qpow(r - l, n);
            for (int i = 0; i < m; i++) {
                int p = (l & ((1 << i) - 1)) - (l & (1 << i)), q = (r & ((1 << i) - 1)) - (r & (1 << i));
                int x = qpow((p + q) % P, n), y = qpow((q - p + P) % P, n);
                int even = 1ll * (x + y) * INV2 % P, odd = 1ll * (y - x + P) * INV2 % P;
                if (!(k >> (i + 1))) {
                    ans = (ans + 1ll * even * (1 << m - 1 - i) % P * ((k >> i & 1) ? P - 1ll : 1ll)) % P;
                }
                if (!((k ^ l ^ r) >> (i + 1))) {
                    ans = (ans + 1ll * odd * (1 << m - 1 - i) % P * (((k ^ l ^ r) >> i & 1) ? P - 1ll : 1ll)) % P;
                }
            }
            ans = 1ll * ans * qpow((1 << m), P - 2) % P;
            printf("%d\n", ans);
        }
    }
    return 0;
}