Martian148's blog Martian148's blog
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档

Martian148

一只热爱文科的理科生
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档
  • codeforses 题解

  • atcoder 题解

  • XCPC 题解

  • 校训练赛题解

  • 牛客题解

  • 蓝桥杯题解

  • 典题选讲

    • CF2025E Card Game (动态规划、多项式快速幂、银牌题)
      • CF2026E Best Subsequence(网络流、最大权闭合图,铜牌题)
    • 杂题

    • 算法题解
    • 典题选讲
    martian148
    2024-10-25
    目录

    CF2025E Card Game (动态规划、多项式快速幂、银牌题)

    # CF2025E Card Game (动态规划、多项式快速幂、银牌题)

    # Question

    CF2025E Card Game (opens new window)

    # Solution

    可以把牌的匹配看成是括号匹配,A 玩家拿的牌看成左括号,B 玩家拿的牌看成右括号

    如果只考虑一种花色的话,一个合理的括号匹配恰好对应一种括号序列

    但是这里一共有 nnn 种花色,需要第 111 种花色多出 kkk 个左括号,剩下的 n−1n-1n−1 种花色一共多出 kkk 个右括号才能匹配

    所以我们这里需要求出一种花色多出 kkk 个左括号的方案数,由于对称性,这个数也等于一种花色多出 kkk 个右括号的方案数

    这个问题可以用 dp 来解决,定义 dp[i][j]dp[i][j]dp[i][j] 表示前 iii 个括号,左括号比右括号多出 jjj 个的方案数,那么很容易可以推出转移方程

    dp[i][j]=dp[i−1][j−1]+dp[i−1][j+1] dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1] dp[i][j]=dp[i−1][j−1]+dp[i−1][j+1]

    于是答案就是 dp[m][k]dp[m][k]dp[m][k] ,我们令 f=dp[m]f=dp[m]f=dp[m]

    那么如何求 ∑i=2nki=K\sum_{i=2}^n k_i=K∑i=2n​ki​=K 满足的方案数,把 fff 看成多项式,这里刚好满足多项式乘法的定义,于是我们把 fn−1f^{n-1}fn−1 就得到了 n−1n-1n−1 个花色,一共有 kkk 个左括号多出来的方案数了

    最后枚举 kkk 累计答案就可以了,答案为 ∑k=0mf[k]×fn−1[k]\sum_{k=0}^m f[k]\times f^{n-1}[k]∑k=0m​f[k]×fn−1[k]

    # Code

    #include <bits/stdc++.h>
    using namespace std;
    
    Z f[N][N], g[N];
    
    int main() {
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        int n, m;
        cin >> n >> m;
    
        f[0][0] = 1;
        for (int i = 1; i <= m; i++) {
            f[i][0] = f[i - 1][1];
            for (int j = 1; j <= i; j++)
                f[i][j] = f[i - 1][j - 1] + f[i - 1][j + 1];
        }
        
        for (int i = 0; i <= m; i++)
            if (1) g[i] = f[m][i];
        
        Poly F; F.resize(m + 1);
        for (int i = 0; i <= m; i++) F[i] = g[i];
    
        F = F.pow(n - 1, m + 1);
    
        Z ans = 0;
        for (int i = 0; i <= m; i++) {
            Z now = F[i] * g[i];
            ans += now;
        }
    
        cout << ans << '\n';
    
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    上次更新: 2025/04/08, 18:03:31
    蓝桥杯2023年第十四届省赛 python B组 题解
    CF2026E Best Subsequence(网络流、最大权闭合图,铜牌题)

    ← 蓝桥杯2023年第十四届省赛 python B组 题解 CF2026E Best Subsequence(网络流、最大权闭合图,铜牌题)→

    最近更新
    01
    Java基础语法
    05-26
    02
    开发环境配置
    05-26
    03
    pink 老师 JavaScript 学习笔记
    05-26
    更多文章>
    Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式