首页 > 其他分享 >CF960G Bandit Blues

CF960G Bandit Blues

时间:2023-08-11 13:44:33浏览次数:40  
标签:int res 最大值 CF960G Bandit 1ll bmatrix Blues ta

半个月前做的题,这段时间一直在颓所以没写题解,今天突然想起来才准备补上。

考虑枚举最大值 \(n\) 的位置 \(i\),那么排列就被分成 \(2\) 个段 \([1,i-1]\) 和 \([i+1,n]\),而且 \(\forall k\in [i+1,n]\),\(k\) 不可能是前缀最大值;\(\forall k\in [1,i-1]\),\(k\) 不可能是后缀最大值。

于是两个段可以互相独立地进行计数。就是说 \([1,i-1]\) 中有 \(a-1\) 个前缀最大值,\([i+1,n]\) 中有 \(b-1\) 个后缀最大值。

令 \(f_{i,j}\) 表示 \(i\) 个数的排列前缀最大值有 \(j\) 个的方案数。枚举 \(n\) 的位置 \(i\),从剩下 \(n-1\) 个数中选 \(i-1\) 个放到 \([1,i-1]\),那么答案就是:

\[\text{ans}=\sum\limits_{i=1}^n\dbinom{n-1}{i-1}f_{i-1,a-1}f_{n-i,b-1} \]

考虑 \(f\) 怎么求,我们从大到小往当前排列 \(P\) 中插入最小值 \(k\),考虑 \(n\) 个数的排列有 \(n+1\) 个位置可以插入:

  • 若 \(k\) 插入到 \(P\) 的开头,新增一个前缀最大值,则 \(f_{i,j}\gets f_{i-1,j-1}\)。
  • 若 \(k\) 插入到 \(P\) 的其它位置,前缀最大值个数不变,则 \(f_{i,j}\gets (i-1)f_{i-1,j}\)。

于是:

\[f_{i,j}=f_{i-1,j-1}+(i-1)f_{i-1,j} \]

看得出来 \(f_{i,j}\) 这东西就是第一类斯特林数 \(\begin{bmatrix}i\\j\end{bmatrix}\)。

那么答案就是:

\[\text{ans}=\sum\limits_{i=1}^n\dbinom{n-1}{i-1}\begin{bmatrix}i-1\\a-1\end{bmatrix}\begin{bmatrix}n-i\\b-1\end{bmatrix} \]

至此,不怕麻烦的同学就可以直接计算 \(a-1,b-1\) 两列的斯特林数,然后卷一下就行了。

如果继续化简,有 \(3\) 种方式:

  • 代数推导(天地灭)
  • 生成函数(天地灭灭灭灭灭灭灭灭)
  • 组合意义(非常的新鲜,非常的美味啊!)

所以我们考虑组合意义。

求和里面那坨就相当于从 \(n-1\) 个数中选 \(i-1\) 个生成 \(a-1\) 个圆排列,剩下 \(n-i\) 个数生成 \(b-1\) 个圆排列的方案数。

按照范德蒙德卷积的思路,相当于 \(n-1\) 个数中先生成 \(a+b-2\) 个圆排列,再从这么多圆排列中选出 \(a-1\) 个的方案数。由于选出来后 \(a-1\) 个圆排列和 \(i\)(\(a-1\) 个圆排列总大小)是对应的,所以既不会重也不会漏。

于是答案就是 \(\begin{bmatrix}n-1\\a+b-2\end{bmatrix}\dbinom{a+b-2}{a-1}\)。

考虑到第一类斯特林数没有实用的通项公式,直接大力把第 \(n-1\) 行算出来就行了。复杂度 \(O(n\log n)\)。

typedef vector<int> poly;
const int G = 114514;
const int P = 998244353;
const int N = 6e5 + 600;

int n, a, b, fac[N], ifac[N];
poly bs;

int qpow(int p, int q) {
    int res = 1;
    for (; q; q >>= 1, p = 1ll * p * p % P)
        if (q & 1) res = 1ll * res * p % P;
    return res;
}

const int iG = qpow(G, P - 2);

void init(int lim) {
    fac[0] = 1;
    for (int i = 1; i <= lim; i++)
        fac[i] = 1ll * fac[i - 1] * i % P;
    ifac[lim] = qpow(fac[lim], P - 2);
    for (int i = lim - 1; ~i; i--)
        ifac[i] = 1ll * ifac[i + 1] * (i + 1) % P;
}

void NTT(int *f, int len, int lim, int op) {
    static int tr[N];
    for (int i = 1; i < len; i++)
        tr[i] = (tr[i >> 1] >> 1) | ((i & 1) << (lim - 1));
    for (int i = 0; i < len; i++) 
        if (i < tr[i]) swap(f[i], f[tr[i]]);
    for (int o = 2, k = 1; k < len; o <<= 1, k <<= 1) {
        int tg = qpow(~op ? G : iG, (P - 1) / o);
        for (int i = 0; i < len; i += o) {
            for (int j = 0, w = 1; j < k; j++, w = 1ll * w * tg % P) {
                int x = f[i + j], y = 1ll * w * f[i + j + k] % P;
                f[i + j] = (x + y) % P, f[i + j + k] = (x - y + P) % P;
            }
        }
    }
    if (~op) return;
    int iv = qpow(len, P - 2);
    for (int i = 0; i < len; i++)
        f[i] = 1ll * f[i] * iv % P;
}

poly Mul(poly x, poly y) {
    static int tx[N], ty[N];
    int len = 1, lim = 0, sx = x.size(), sy = y.size();
    while (len < (sx + sy)) len <<= 1, lim++;
    memset(tx, 0, sizeof(int) * (len + 10));
    memset(ty, 0, sizeof(int) * (len + 10));
    for (int i = 0; i < sx; i++) tx[i] = x[i];
    for (int i = 0; i < sy; i++) ty[i] = y[i];
    NTT(tx, len, lim, 1), NTT(ty, len, lim, 1);
    for (int i = 0; i < len; i++)
        tx[i] = 1ll * tx[i] * ty[i] % P;
    NTT(tx, len, lim, -1);
    poly res;
    for (int i = 0; i < sx + sy - 1; i++) res.pb(tx[i]);
    return res;
}

poly conq(int len) {
    if (len == 1) return bs;
    if (len & 1) {
        poly tp = conq(len - 1), res;
        res.pb(1ll * tp[0] * (len - 1) % P);
        for (int i = 1; i < len; i++) 
            res.pb((tp[i - 1] + 1ll * tp[i] * (len - 1) % P) % P);
        res.pb(tp[len - 1]);
        return res;
    }
    poly tp = conq(len >> 1), ta, tb, tc;
    int res = 1;
    for (int i = 0; i <= (len >> 1); i++)
        ta.pb(1ll * tp[i] * fac[i] % P), tb.pb(1ll * res * ifac[i] % P), res = 1ll * res * (len >> 1) % P;
    reverse(ta.begin(), ta.end());
    ta = Mul(ta, tb);
    for (int i = 0; i <= (len >> 1); i++)
        tc.pb(1ll * ifac[i] * ta[(len >> 1) - i] % P);
    return Mul(tp, tc);
}

int C(int n, int m) {
    if (n < m || m < 0) return 0;
    return 1ll * fac[n] * ifac[m] % P * ifac[n - m] % P;
}

int main() {
    n = rd(), a = rd(), b= rd(), init(n << 1), bs = poly(2, 1), bs[0] = 0;
    if (n == 1) {
        if (a == 1 && b == 1) puts("1");
        else puts("0");
        return 0;
    }
    if (a + b - 2 > n) return puts("0"), 0;
    poly ans = conq(n - 1);
    wr(1ll * ans[a + b - 2] * C(a + b - 2, a - 1) % P);
	return 0;
}

标签:int,res,最大值,CF960G,Bandit,1ll,bmatrix,Blues,ta
From: https://www.cnblogs.com/Ender32k/p/17622769.html

相关文章

  • Vulnhub: DriftingBlues: 6靶机
    kali:192.168.111.111靶机:192.168.111.180信息收集端口扫描nmap-A-sC-v-sV-T5-p---script=http-enum192.168.111.180查看robots.txt发现存在目录:/textpattern/textpattern访问后发现是textpatterncms目录爆破发现文件spammer,访问后发现是个压缩包,解压需要密码,......
  • Bandit靶场攻略实况
    Bandit靶场攻略实况前言:在开始攻略Bandit之前,我在这里给大家介绍一个学习linux命令的宝藏网站,有什么命令不懂,可以马上翻阅此网站!非常实用!网址:https://www.runoob.com/linux/linux-command-manual.html1. 打开MobaXterm终端模拟器,选择session2. 选择SSH,“Remotehost”为......
  • 渗透笔记:vulnhub靶机drippingblues--第一篇测试记录
    在不知道靶场的ip情况下进行扫描 出现有几个ip,但是不知道哪个是的,所以就一个个试一试namp-T4-sV-A-O-p- 192.168.13.143-T4(速度) -sV(版本扫描和开启的服务) -O(操作系统) -p-(所有端口)扫了好几个,只有一个是的,所以不是的就没有发出来了 ftp一下ip,发现有一......
  • OverTheWire攻关过程-Bandit模块33
    我们打开lv32-lv33,查看信息机器翻译在所有这些git的东西之后,是时候再次逃脱了。祝你好运!您可能需要解决此级别的命令嘘,伙计看来是需要sh命令先了解下sh命令我们登陆服务器查看信息已进入就是shell尝试了几个,发现不行输入$0可以得到正常的shellcat/etc/bandit_pass/bandit33得到密......
  • OverTheWire攻关过程-Bandit模块31
    我们打开lv30-lv31,查看信息机器翻译有一个git仓库在ssh://bandit30-git@localhost/home/bandit30-git/repo经由端口2220。用户bandit30-git的密码与用户bandit30的密码相同。克隆存储库并找到下一级别的密码。您可能需要解决此级别的命令git的一样的使用git命令我们登陆服务器查......
  • Bandit闯关攻略
    level0XSHELL直接连接主机名bandit.labs.overthewire.org端口 2220用户名密码为 bandit0 0-1 ls查看文件cat文件名1-2ls查看文件名,发现文件名为-无法时间cat需要cat./-转义2-3 ls查看文件名文件名称有空格需要每个空格加\直接TAB补齐即可3-4 隐......
  • OverTheWire攻关过程-Bandit模块29
    我们打开lv28-lv29,查看信息机器翻译有一个git仓库在ssh://bandit28-git@localhost/home/bandit28-git/repo经由端口2220。用户bandit28-git的密码与用户bandit28的密码相同。克隆存储库并找到下一级别的密码。您可能需要解决此级别的命令git的我们登陆服务器没有文件git拉取到本......
  • OverTheWire攻关过程-Bandit模块28
    我们打开lv27-lv28,查看信息机器翻译有一个git仓库在ssh://bandit27-git@localhost/home/bandit27-git/repo经由端口2220。用于用户匪27-git的密码与用于用户匪27的相同。克隆存储库并找到下一级别的密码。我们登陆服务器没有发现文件我们查看信息ssh://bandit27-git@localhost/ho......
  • OverTheWire攻关过程-Bandit模块27
    我们打开lv26-lv27,查看信息机器翻译好工作得到一个壳!现在赶紧抢匪27的密码!我们登陆服务器我们发现一登录就发现断开猜想,有没有可能跟25关卡一样由于tabby的窗口不是系统的原生窗口我们输入V,进入编辑模式:setshellsh=/bin/sh使用ls查看文件可以看到有sudo执行的文件使用命令./ban......
  • OverTheWire攻关过程-Bandit模块26
    我们打开lv25-lv26,查看信息使用机器翻译从bandit25登录bandit26应该相当容易......用户bandit26的shell不是/bin/bash,而是别的东西。找出它是什么,它是如何工作的,以及如何打破它。您可能需要解决此级别的命令ssh,cat,more,vi,ls,id,pwd可以知道,可能是已登录就被踢出所以我们了解下信息登......