「解题报告」ARC134F Flipping Coins

简单题。

但是我不会。

首先考虑这个过程:我们从前往后扫,只要有正面就给翻成反面,那么最后留下的正面只有可能是当 \(p_i < i\)\(i\) 没有被翻面时才会造成 \(1\) 的贡献。

而我们发现,如果有一段链,那么第一个硬币会翻第二个硬币,第三个硬币会翻第四个硬币,只有当链为奇数时最后一个硬币才不会被翻,也就造成了 \(1\) 的贡献。

那么我们考虑将一个排列看做若干个置换环,然后将这个环从最小值的地方断开,这样一个排列中正面的数量就是所有置换环中极长上升子段且长度为奇数的个数。

考虑将这些置换环按照最小值从大到小的顺序排成一个新的排列。容易发现这样是一个双射,因为可以通过前缀最小值的位置确定每个置换环的分割点,从而还原出原排列。

比如原序列 \(p = \{2, 4, 5, 1, 3\}\),它的置换环为 \((1, 2, 4), (3, 5)\),新排列为 \(\{3, 5, 1, 2, 4\}\)

那么我们就只需要对所有的排列,统计其极长上升子段且长度为奇数的个数。

发现长度为偶数时并不会造成任何贡献,而且我们不关心长度,只关心奇偶性,那么我们考虑将每一个极长上升子段分成长为 \(2\)\(1\) 的小段,这样我们要统计的实际上就是长度为 \(1\) 的段数。

具体的,我们令长为 \(2\) 的小段的前一个数为 \(A\),后一个数为 \(B\),令长为 \(1\) 的小段为 \(C\),那么我么发现每个序列可以看做为若干个 \(AB\) 和若干个 \(C\) 的组合。

我们只需要满足 \(A < B\)(子段需要是上升的)和 \(C\) 大于后一个数(否则可以匹配成 \(AB\))即可。如果我们从每一个 \(AB\) 的后面断开,那么发现这若干个序列之间的相对大小关系不重要,原序列会长成 \((CC\cdots CAB)(CC\cdots CAB) \cdots (CC\cdots CAB) (CC\cdots)\) 的形式。我们设 \(F(x)\) 为整个序列的 EGF,\(G(x)\)\(CC\cdots CAB\) 的 EGF,\(H(x)\)\(CC\cdots\) 的 EGF,那么显然有 \(F(x) = F(x)G(x) + H(x), F(x) = \frac{H(x)}{1-G(x)}\),且 \(G(x)\)\(H(x)\) 是容易计算的(\([\frac{x^n}{n!}] G(x) = (n - 1) w^{n - 2},[\frac{x^n}{n!}] H(x) = w^{n}\)),直接求即可。

int fac[MAXN], inv[MAXN];
int n, w;
int main() {
    scanf("%d%d", &n, &w);
    fac[0] = 1;
    for (int i = 1; i <= n; i++)
        fac[i] = 1ll * fac[i - 1] * i % P;
    inv[n] = qpow(fac[n], P - 2);
    for (int i = n; i >= 1; i--)
        inv[i - 1] = 1ll * inv[i] * i % P;
    f.set(n), g.set(n);
    for (int i = 2; i <= n; i++)
        f[i] = 1ll * (i - 1) * qpow(w, i - 2) % P * inv[i] % P;
    for (int i = 0; i <= n; i++)
        g[i] = 1ll * qpow(w, i) * inv[i] % P;
    f = (f * (P - 1) + 1).inv(n + 1) * g;
    printf("%lld\n", 1ll * f[n] * fac[n] % P);
    return 0;
}
posted @ 2023-02-25 11:45  APJifengc  阅读(54)  评论(0编辑  收藏  举报