太喜欢这个题了,这个题出得很启发性,我以前还没见过,于是把这个题记录下来。

题面

在伯兰最流行的纸牌游戏中,使用的是一副 \(n \times m\) 纸牌。每张牌都有两个参数:花色和等级。游戏中花色的编号从 \(1\) 到 \(n\),等级的编号从 \(1\) 到 \(m\)。每种花色和等级的组合都有一张牌。

  • \(a = 1\), \(c \ne 1\) (花色为 \(1\) 的牌可以战胜其他花色的牌);
  • \(a = c\), \(b > d\) (一张牌可以击败同花色但等级较低的任何其他牌).

两名玩家进行游戏。游戏开始前,他们每人正好得到一半的牌。如果第一位玩家可以为第二位玩家的每一张牌选择一张可以击败它的牌,并且没有被选择两次的牌(即第一位玩家的牌与第二位玩家的牌存在配对,在每一对牌中,第一位玩家的牌击败第二位玩家的牌),则第一位玩家获胜。否则,第二名玩家获胜。

你的任务是计算有多少种分配牌的方法能让第一名玩家获胜。如果有一张牌在一种分配方式中属于第一名玩家,而在另一种分配方式中属于第二名玩家,那么这两种分配方式就被认为是不同的。方法的数量可能非常大,输出答案对 \(998244353\) 的模。

唯一一行包含两个整数 \(n\) 和 \(m\) (\(1 \le n, m \le 500\)) 为偶数。

输入的其他限制条件:\(m\) 为偶数。

题解

这个题乍一看很 \(dp\) 但是实际上这个题可以用组合数学推出答案。

对同样花色的牌,考虑什么情况下才能获胜,显然是对于所有的先手 (\(A\)) 的牌都可以找到一个后手 (\(B\)) 的牌使得 \(A\) 的牌面比 \(B\) 大,考虑括号匹配。

对于任意一个前缀 \(A\) 选择第 \(i\) 张牌则第 \(i\) 位置为左括号,否则被 \(B\) 选择就是右括号,对于任意前缀,必定满足左括号数不小于右括号数,考虑状态转移。

记 \(dp[i][j]\) 表示考虑的前 \(i\) 个位置,其中有 \(j\) 个左括号赘余(没有被右括号匹配),则对于下一个位置要么增加一个左括号,要么减少一个左括号,状态转移如下:

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

我们选择第一行的牌(花色为 \(1\))的时候的所有情况被 \(dp\) 数组所包含,接下来考虑剩下第 \(2 \sim n\) 行的牌,此部分 \(A\) 必不可能多选,否则必定存在一张牌不能在同行匹配,会被 \(B\) 用一张 \(1\) 匹配,所以此时右括号赘余,考虑前面所有 \(A\) 的牌会被抵消掉,仅仅把多余的牌替换为 \(B\) 的牌即可,也就是说这一部分的贡献和第一行完全一样,考虑对第 \(2 \sim n\) 行的方案数卷积,即:

\[f[k] = \sum_{x + y = k}g[x] \times h[y]
\]

这个转移是直觉的,因为对两行分别赘余 \(x\), \(y\) 张牌,总共赘余的牌有 \(x + y\) 张,而由于所有的行是相同的,做 \(n - 1\) 次卷积:

\[\forall k \le m, f[i][k] = \sum_{x + y = k} f[i - 1][x] * dp[m][y]
\]

最后我们的答案需要第一行赘余的左括号与其余行赘余的右括号完全匹配,可以列出:

\[answer = \sum_{i = 0}^{m}dp[m][i] * f[n - 1][i]
\]

参考代码(滚动数组优化)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 510;
const ll mod = 998244353;
int n, m; int main()
{
cin >> n >> m;
vector<ll> dp(m + 1), f(m + 1);
dp[0] = f[0] = 1;
for (int i = 0; i < m; i ++ )
{
vector<ll> tmp(m + 1);
for (int j = 0; j <= i; j ++ )
{
(tmp[j + 1] += dp[j]) %= mod;
if (j) (tmp[j - 1] += dp[j]) %= mod;
}
swap(tmp, dp);
}
for (int i = 1; i < n; i ++ )
{
vector<ll> tmp(m + 1);
for (int x = 0; x <= m; x ++ )
for (int y = 0; x + y <= m; y ++ )
(tmp[x + y] += f[x] * dp[y] % mod) %= mod;
swap(tmp, f);
}
ll ans = 0;
for (int i = 0; i <= m; i ++ ) (ans += dp[i] * f[i] % mod) %= mod;
cout << ans;
return 0;
}

CF2025E Card Game 题解的更多相关文章

  1. Clash Credenz 2014 Wild Card Round题解

    A题 简单模拟. /************************************************************************* > File Name: ...

  2. CF1492B Card Deck 题解

    Content 有 \(n\) 张纸牌组成的一个牌堆,每张纸牌都有一个价值 \(p_1,p_2,\dots,p_n\).每次选出最顶上的几个牌放到另外一个一开始为空的牌堆里面.定义一个牌堆的总值为 \ ...

  3. CF106A Card Game 题解

    Content 一种纸牌游戏有许多张卡牌,每张卡牌有一个套装(S,H,D和 C)和一个等级(按升序排列6,7,8,9,T, J,Q,K,A). 规定以下情况卡牌 A 才能赢卡牌 B: A 有王牌套装, ...

  4. MinMax 容斥 学习笔记

    基本形式 \[ \max(S) = \sum_{T\subseteq S, T \neq \varnothing} (-1)^{|T|-1}\min(T) \] 证明 不提供数学证明. 简要讲一下抽象 ...

  5. 【题解】P3129高低卡(白金)High Card Low Card

    [题解][P3129 USACO15DEC]高低卡(白金)High Card Low Card (Platinum) 考虑贪心. 枚举在第几局改变规则,在改变规则之前,尽量出比它大的最小的牌,在改变规 ...

  6. HDU 4336 Card Collector(状压 + 概率DP 期望)题解

    题意:每包干脆面可能开出卡或者什么都没有,一共n种卡,每种卡每包爆率pi,问收齐n种卡的期望 思路:期望求解公式为:$E(x) = \sum_{i=1}^{k}pi * xi + (1 - \sum_ ...

  7. 【题解】HDU4336 Card Collector

    显然,这题有一种很简单的做法即直接状压卡牌的状态并转移期望的次数.但我们现在有一个更加强大的工具——min-max容斥. min-max 容斥(对期望也成立):\(E[max(S)] = \sum_{ ...

  8. [OpenJudge 3061]Flip The Card

    [OpenJudge 3061]Flip The Card 试题描述 There are N× Ncards, which form an N× Nmatrix. The cards can be p ...

  9. cdoj 31 饭卡(card) 01背包

    饭卡(card) Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/31 Des ...

  10. 《ACM国际大学生程序设计竞赛题解Ⅰ》——基础编程题

    这个专栏开始介绍一些<ACM国际大学生程序设计竞赛题解>上的竞赛题目,读者可以配合zju/poj/uva的在线测评系统提交代码(今天zoj貌似崩了). 其实看书名也能看出来这本书的思路,就 ...

随机推荐

  1. PySide6/PyQt开发经验总结(2) - 设置快捷键

    Qt设置快捷键 本文仅供本人知识总结使用,所以内容会比较浅显,不喜勿喷. 目录 Qt设置快捷键 一.需要的类 QShortcut 函数: 二.设置快捷键 官方文档原文翻译: 我的理解: 一.需要的类 ...

  2. java_类方法&对象方法

    int new; 类方法 不能写入和访问其中的对象属性 可以直接通过类调用 通过类调用类方法,没有具体的对象, 所以 不可以访问对象属性, 但是可以访问类属性 public static void d ...

  3. TwinCAT3 - 实现CiA402

    目录 1,起缘 2,想办法 3,开搞 3.1,CANOpen通信 3.1.1 对象字典 3.1.2 通信建立 3.2,CiA402伺服状态机 3.3,伺服运行 3.3.1 操作模式 3.3.2 轮廓位 ...

  4. Ubuntu 写入磁盘映像

    使用 dd 命令 dd 命令是 Unix 和 Unix-like 操作系统中用于低级别数据复制和转换的命令.它可以直接操作设备文件(如硬盘.光盘.USB 驱动器等),适用于备份.恢复.制作启动盘等任务 ...

  5. electron修改vue项目打包后的exe图标

    vue用electron打包点击这里 安装electron-icon-builder 添加图标生成器:npm i electron-icon-builder 生成图标 1.在package.json的 ...

  6. qumu虚拟机启动后无法远程连接

    通过 virsh 在启动 qemu 虚拟机,可以通过 VNC 访问虚拟机,但无法通过设置的 SSH 的外部映射端口登录.首先在宿主机上查看虚拟机(csv\tpm\name)的网络配置,可以看到端口映射 ...

  7. DLA:动态层级注意力架构,实现特征图的持续动态刷新与交互 | IJCAI'24

    论文深入探讨了层级注意力与一般注意力机制之间的区别,并指出现有的层级注意力方法是在静态特征图上实现层间交互的.这些静态层级注意力方法限制了层间上下文特征提取的能力.为了恢复注意力机制的动态上下文表示能 ...

  8. java基础 -反射笔记

    710,反射快速入门 代码: 先创建一个 re.properties 文件: classfullpath=com.hspedu.Cat method=hi Cat.java package com.h ...

  9. SqlEs-像使用数据库一样使用Elasticsearch

    SqlEs SqlEs是Elasticsearch的客户端JDBC驱动程序,支持采用sql语法操作Elasticsearch.SqlEs构建在RestHighLevelClient,屏蔽了RestHi ...

  10. [OI] pb_ds

    using namespace __gnu_pbds; Luogu Post#39 1.堆 1.1 基本信息 头文件 #include <ext/pb_ds/priority_queue.hpp ...