「解题报告」CF960G Bandit Blues

无脑的 APJ 用最无脑的方法解题!!!做了两天图论脑子爆炸后的 apj 寻求精神慰藉

首先考虑 n 一定是从前往后的最大值与从后往前的最大值,这样我们只需要求出长度为 n,有 k 个前缀最大值的排列数量,记作 fn,k

考虑每次将当前排列中的最大值与最大值后面的排列去掉,这样就能递归到一个子问题里。例如 1,4,2,6,3,5,我们可以将 6,3,5 删去。枚举删去的后缀的长度 i,那么后缀本身的方案有 (i1)! 种,将后缀与前缀混合在一起的方案数为 (n1i1),所以我们可以得出转移式子:

fn,k=i=1n(n1i1)(i1)!fni,k1

然后把组合数拆一下,移项,得:

fn,kn!=1ni=1nfni,k1(ni)!

后面求和指标换一下:

fn,kn!=1ni=0n1fi,k1i!

然后无脑写成生成函数,设 Fk(x)=i0fi,ki!xi,那么容易推出:

Fk(x)=Fk1(x)1xdx

这个式子直接做看起来还是不可做。我们代具体的式子进去试试:

由于有 F0(x)=1,那么有:

F1(x)=11xdx=ln(1x)F2(x)=ln(1x)1xdx=(ln(1x))(ln(1x))dx=udu=u22=(ln(1x))22F3(x)=(ln(1x))22(1x)=u22du=u36=(ln(1x))36

由此归纳可以得出 Fk(x)=(ln(1x))kk!

回到原问题来,我们枚举了中间的最大值的位置 i,那么答案应该为 i=1nfi1,a1fni,b1(n1i1),发现这其实就等于 (n1)![xn1]Fa1(x)Fb1(x)=(n1)![xn1](ln(1x))a+b2(a1)!(b1)!,后者直接多项式快速幂即可。容易 O(nlogn)

其实最后还是第一类斯特林数,我这是不是相当于自己把第一类斯特林数的生成函数推导了一遍啊,呃呃。

int main() {
    scanf("%d%d%d", &n, &a, &b);
    if (a == 0 || b == 0 || n - a - b + 1 < 0) {
        printf("0\n");
        return 0;
    }
    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 - 1);
    for (int i = 0; i < n; i++) f[i] = qpow(i + 1, P - 2);
    f = f.pow(a + b - 2, n);
    printf("%lld\n", 1ll * fac[n - 1] * f[n - a - b + 1] % P * inv[a - 1] % P * inv[b - 1] % P);
    return 0;
}
posted @   APJifengc  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示