首页 > 编程语言 >CCSP2019T2_纸牌计数 | 2019苏州CCSP大学生计算机系统与程序设计竞赛

CCSP2019T2_纸牌计数 | 2019苏州CCSP大学生计算机系统与程序设计竞赛

时间:2023-06-09 17:22:31浏览次数:50  
标签:1P 1S 0P 0C 1C CCSP 2019 字符串 CCSP2019T2

题目描述

偶然在CSDN看到有人写了CCSP2019T2_纸牌计数的题解,突然想起来是一个不错的计数、dp题。
以前的U盘找不到了,记得当时存了一步步偏分到AC代码,可惜。又想起来18年打铁了。。。
此人的题解的链接 CCSP201902纸牌计数——解题报告
当年一共有5题,取自:https://www.sohu.com/a/347851686_610300
T1: 摘水果 fruit
T2:纸牌计数 card
T3:系统实现题 SQL 查询
T4:系统策略题 调度器 scheduler
T5:系统结构体 评测鱼 risc-v
T2的题面:

Description
我们有一副纸牌,它由 n 张牌组成,其中每张牌上标有一个数字(0 到 9)和一个大写字母(A 到 Z),例如 2C、1F。

我们如下定义一个字符串与一张牌之间的匹配关系:
字符串 ?? 与任何一张牌都匹配。
第一位为 ? 而第二位为字母的字符串,与任何一张标有该字母的牌匹配。例如,字符串 ?C 与任何标有 C 的牌匹配。
第一位为数字而第二位为字母的字符串,仅与内容完全一致的牌匹配。例如,字符串 0C 与内容为 0C 的牌匹配。
不会出现第一位为数字而第二位为 ? 的字符串。
我们称 m 个字符串 S1 ... Sm 与 m 张牌 C1 ... Cm 是匹配的,当且仅当:存在集合 { 1 , … , m } 上的一一映射 σ,使得对于任意 1 ≤ i ≤ m ,Si 与 C_σ(i) 匹配。

例如,对于 ?? 和 ?C 这两个字符串,可以匹配内容为 1C 和 2C 的牌,因为字符串 ?? 与内容为 2C 的牌匹配且字符串 ?C 与内容为 1C 的牌匹配,而 ?? 和 ?C 这两个字符串不能匹配内容为 1S 和 1P 的牌。

现在,给定 m 个字符串,你需要求解:如果在 n 张牌中(无放回地)随机选取 m 张,有多大概率与这些字符串匹配?

Input
每个输入文件包含多个输入数据。
第一行输入该文件的数据个数 T。
接下来依次输入每个数据。每个数据包含三行,其中:
第一行输入两个正整数 n 和 m;
第二行输入以空格分隔的 n 个字符串,表示每张纸牌的内容(每个字符串第一位为数字,第二位为大写字母);
第三行输入以空格分隔的 m 个字符串,表示每个需要匹配的字符串(每个字符串第一位为数字,第二位为大写字母;或第一位为 ?,第二位为大写字母;或为 ??)。

Output
对于每个输入数据,输出一行,表示所求的概率。概率需要以最简分数 u/v 的形式输出,其中 0 ≤ u ≤ v 且 u, v 为互质的整数。
特殊地,对于 0 请输出 0/1,对于 1 请输出 1/1。

Subtasks
对于所有的数据,1 <= m <= n <= 60, T <= 1000, $1 \leq m \leq n \leq 60; T \leq 1000$。
(11分)m=1;
(23分)m=n;
(27分)n=30 且所有的牌为 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P;
(22分)n=40 且所有的牌为 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P;
(17分)没有特殊的限制。

题解

一时间不记得咋写的了,按记忆口胡了一个做法,感觉复杂度有点假,但好像跑不满,以后再看看吧:

  • 求概率/期望的时候,两个独立事件(即正交的情况)可以分开考虑,答案为每个事件概率的乘积。类似于积性函数中的一些理念。
  • n张牌的字母都是固定的,一般m个字符串的字母也是固定的(除非是两个问号??)。
  • 考虑是否可以先分26个字母考虑,再考虑??。
  • rdp[j][k] 表示考虑到数字j用了k个问号的(不)合法情况数(合不合法,即是否存在重复计数的),把单个?的情况用组合数计数分配一下
  • 现在 ?? 还没处理吧,所以??可以在这个层次上再套一层dp
  • val[i][w] 表示考虑到字母i已经用了w个??的合法方案数,最后背包dp一遍求答案
  • (不确定有没有爆 long long,感觉复杂度可以减掉一个60?
#include <bits/stdc++.h>
#define fi first
#define se second
#define o2(x) (x) * (x)
#define mk make_pair
#define eb emplace_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a), (b), sizeof((a)))
#define rep(i, s, t) for(register int i = (s), LIM=(t); i < LIM; ++i)
#define per(i, s, t) for(register int i = (s), LIM=(t); i > LIM; --i)
#define GKD std::ios::sync_with_stdio(false);cin.tie(0)
#define my_unique(x) sort(all(x)), x.erase(unique(all(x)), x.end())
using namespace std;
typedef long long LL;
typedef long long int64;
typedef unsigned long long uint64;
typedef pair<int, int> pii;
// mt19937 rng(time(NULL));//std::clock()
// mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());
// shuffle(arr, arr + n, rng64);
inline int64 read() {
    int64 x = 0;int las = 0;char ch = getchar();
    while (ch < '0' || ch > '9') las |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch =
    getchar(); return x = las ? -x : x;
}
inline void write(int64 x, bool las = true) {
    if (x == 0) {putchar('0'); if(las)putchar('\n');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(las)putchar('\n');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template <class T>
T big(const T &a1, const T &a2) {return a1 > a2 ? a1 : a2;}
template <class T>
T sml(const T &a1, const T &a2) {return a1 < a2 ? a1 : a2;}
template <typename T, typename... R>
T big(const T &las, const R &... r) {return big(las, big(r...));}
template <typename T, typename... R>
T sml(const T &las, const R &... r) {return sml(las, sml(r...));}
void debug_out() { cout << '\n'; }
template <typename T, typename... R>
void debug_out(const T &las, const R &... r) {
    cout << las << " ";
    debug_out(r...);
}
#ifdef LH_LOCAL
#define debug(...) cout << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
#else
#define debug(...) ;
#endif
#define debug(...) ;
/*================Header Template==============*/
const int mod = 998244353;// 998244353
int ksm(int a, int64 b, int kmod = mod) {int res = 1;for(;b > 0;b >>= 1, a = (int64)a * a % kmod) if(b &1) res = (int64)res * a % kmod;return res;}
const int INF = 0x3f3f3f3f;
const int MXN = 2e5 + 5;
const int MXM = 5e6 + 7;
int n, m;
char card[65][3], str[65][3];
// 0 <= . <= 9, A <= . <= Z  -> 1 <= . <= 10
int cnt[30][15], need[30][15];
int sum[2][30];
LL fdp[30], rdp[15][65], val[30][65], dp[30][65];

LL COMB(int n, int m) {
    if(n == m) return 1;
    if(n < m) return 0;
    LL res = 1;
    for(int i = 0; i < m; ++i) {
        res *= (n - i);
        res /= i + 1;
    }
    return res;
}

void work() {
    n = read(), m = read();
    for(int i = 1; i <= n; ++i) scanf("%s", card[i]);
    for(int i = 1; i <= m; ++i) scanf("%s", str[i]);
    int flag = 1;
    for(int i = 1; i <= n; ++i) {
        cnt[card[i][1] - 'A'][card[i][0] - '0' + 1] ++;
        sum[0][card[i][1] - 'A'] ++;
    }
    LL ww = m;
    for(int i = 1; i <= m; ++i) {
        if(str[i][1] != '?') {
            if(str[i][0] != '?') need[str[i][1] - 'A'][str[i][0] - '0' + 1] ++;
            else need[str[i][1] - 'A'][0] ++;
            sum[1][str[i][1] - 'A'] ++;
            ww --;
        }
    }
    LL res = 1;
    for(int i = 0; i < 26; ++i) {
        if(sum[0][i] < sum[1][i]) {
            flag = 0;
            break;
        }
        for(int w = 0; w <= ww; ++w) {
            need[i][0] += w;
            fdp[i] = 1;
            memset(rdp, 0, sizeof(rdp));
            rdp[0][0] = 1;
            // rdp[j][k] 表示考虑到数字j用了k个问号的(不)合法情况数(合不合法,即是否存在重复计数的)
            // 把单个?的情况用组合数计数分配一下
            // ?? 还没处理吧,所以??可以在这个层次上再套一层dp
            // val[i][w] 表示考虑到字母i已经用了w个??的合法方案数
            for(int j = 1; j <= 10; ++j) {
                if(cnt[i][j] < need[i][j]) {
                    flag = 0;
                    break;
                }
                fdp[i] = fdp[i] * COMB(cnt[i][j], need[i][j]);
                // for(int k = 0; k <= need[i][0]; ++k) rdp[j][k] = rdp[j - 1][k];
                if(1 || cnt[i][j] > need[i][j] && need[i][j] > 0) {
                    for(int h = 0; h <= cnt[i][j] - need[i][j]; ++h) {
                        for(int k = h; k <= need[i][0]; ++k) {
                            rdp[j][k] = rdp[j][k] + rdp[j - 1][k - h] * COMB(cnt[i][j], need[i][j] + h);
                            // debug(h, j, k, rdp[j][k])
                        }
                    }
                    // if(i == 'C' - 'A') debug(j)
                }else {
                    // if(i == 'C' - 'A') debug(j, rdp[j][1], rdp[j - 1][1])
                }
            }
            // rdp[10][0] = 0;
            fdp[i] = fdp[i] * COMB(sum[0][i] - (sum[1][i] - need[i][0]), need[i][0]);
            LL ret = rdp[10][need[i][0]];
            if(i == 'C' - 'A') debug(i, w, need[i][0], fdp[i], rdp[10][need[i][0]], fdp[i] - rdp[10][need[i][0]], ret, fdp[i] - ret)
            res *= (ret);
            need[i][0] -= w;
            val[i][w] = ret;
            if(i == 'C' - 'A' && val[i][w] > 1) debug(i, w, val[i][w])
        }
    }
    for(int j = 0; j <= ww; ++j) dp[0][j] = val[0][j];
    for(int i = 1; i < 26; ++i) {
        for(int j = 0; j <= ww; ++j) {
            for(int k = 0; k <= j; ++k) {
                dp[i][j] = dp[i][j] + dp[i - 1][j - k] * val[i][k];
            }
        }
    }
    res = dp[25][ww];
    LL allcase = COMB(n, m);
    LL agcd = __gcd(allcase, res);
    debug(allcase, res, res / agcd, allcase / agcd)
    if(flag == 0) {
        printf("0/1\n");
    }else {
        printf("%lld/%lld\n", res / agcd, allcase / agcd);
    }
    // 不确定有没有爆 long long
    for(int i = 0; i < 26; ++i) {
        sum[0][i] = sum[1][i] = 0;
        for(int j = 0; j <= 10; ++j) {
            cnt[i][j] = need[i][j] = 0;
        }
        for(int j = 0; j <= ww; ++j) {
            val[i][j] = 0;
            dp[i][j] = 0;
        }
    }
}

int main() {
#ifdef LH_LOCAL
    freopen("c:/lh/system-lab/acm_code/OJ/in.txt", "r", stdin);
    // freopen("c:/lh/system-lab/acm_code/OJ/out.txt", "w", stdout);
#endif
    for(int cas = 1, tim = (1 ? read(): 1); cas <= tim; ++ cas) {
        work();
    }
    // 56160000
    debug(26*60*10*60*60)
#ifdef LH_LOCAL
    cout << "Debug log: time cost:" << 1.0 * clock() / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}
/*
3
40 2
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P
?C 1C
40 16
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P
0C 0C 1C 2C ?C ?C ?C ?C 3S 4S ?S ?S 5P 6P ?P ?P
60 30
1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U 1V 1W 1X 1Y 1Z 0A 1A 2A 3A 4A 5A 6A 7A 8A 9A 1S 3S 5S 7S 9S 0U 2U 4U 6U 8U 2Z 3Z 5Z 7Z 1C 1C 1C 1C 1C 1C 1C 1C 1S 1P
1C 1C 1S 1P 2A 0A 1A 9A ?S ?U ?Z ?H ?O ?U ?? ?? ?? ?? ?? ?? ?S ?S ?S ?U ?U ?U ?Z ?Z ?C ?C

37/780
167384/2417388525  -> 4351984/x -> 5551 * 28 * 28
50442363273/29566145391215356 -> 201769453092/x

Sample
Input
15
6 1
0C 0S 0P 1C 1S 1P
1S
6 1
0C 0S 0P 1C 1S 1P
?C
6 2
0C 0S 0P 1C 1S 1P
?C ?C
6 2
0C 0S 0P 1C 1S 1P
?C ?S
6 4
0C 0S 0P 1C 1S 1P
?C ?C ?S ?P
6 4
0C 0S 0P 1C 1S 1P
0C ?C ?S ?P
6 4
0C 0S 0P 1C 1S 1P
?C ?C ?S ??
6 4
0C 0S 0P 1C 1S 1P
?C ?C ?? ??
6 4
0C 0S 0P 1C 1S 1P
?A ?? ?? ??
6 4
0C 0S 0P 1C 1S 1P
0C 0C ?S ?P
30 8
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P
0C ?C ?C ?C 1S ?S 2P ?P
40 2
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P
?C 1C
40 2
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P
?C 1S
40 16
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0C 1C 2C 3C 4C 5C 6C 7C 8C 9C 0S 1S 2S 3S 4S 5S 6S 7S 8S 9S 0P 1P 2P 3P 4P 5P 6P 7P 8P 9P
0C 0C 1C 2C ?C ?C ?C ?C 3S 4S ?S ?S 5P 6P ?P ?P
60 30
1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U 1V 1W 1X 1Y 1Z 0A 1A 2A 3A 4A 5A 6A 7A 8A 9A 1S 3S 5S 7S 9S 0U 2U 4U 6U 8U 2Z 3Z 5Z 7Z 1C 1C 1C 1C 1C 1C 1C 1C 1S 1P
1C 1C 1S 1P 2A 0A 1A 9A ?S ?U ?Z ?H ?O ?U ?? ?? ?? ?? ?? ?? ?S ?S ?S ?U ?U ?U ?Z ?Z ?C ?C
Output
1/6
1/3
1/15
4/15
4/15
4/15
1/3
2/5
0/1
0/1
252/216775
37/780
1/39
167384/2417388525
50442363273/29566145391215356

Hint
对于分数 a/b,设 g=gcd(a,b),那么其最简分数形式为 (a/g)/(b/g)。


*/

标签:1P,1S,0P,0C,1C,CCSP,2019,字符串,CCSP2019T2
From: https://www.cnblogs.com/Cwolf9/p/17469780.html

相关文章

  • P5518 [MtOI2019]幽灵乐团 / 莫比乌斯反演基础练习题
    简要题意计算\[\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}\left(\frac{\text{lcm}(i,j)}{\gcd(i,k)}\right)^{f(type)}\]其中:\[\begin{aligned}f(0)&=1\crf(1)&=i\timesj\timesk\crf(2)&=\gcd(i,j,k)\end{aligned}\]\(T\)组数据,每......
  • 2019精选书籍推荐
    距离2020年还剩2个月的时间,整理了今年读过的书籍,精选了18本我认为比较好的书,推荐给大家。年纪大了,只看书不做笔记似乎已经不行了,记忆力下降的很快,有时候一本书读完,居然没记住多少内容。所以接下来的精读的书籍我都要做读书笔记了。人与人的差别是思维方式的差别,而思维方式来源于......
  • 程序员小灰2019年整理
    漫画:寻找无序数组的第k大元素(修订版漫画:如何将一个链表“逆序”?漫画:什么是加密算法?漫画:什么是“图”?(修订版)漫画:深度优先遍历和广度优先遍历漫画:图的“最短路径”问题漫画:Dijkstra算法的优化漫画:图的“多源”最短路径漫画:有趣的“切蛋糕“问题漫画:什么是二分查找?(修订版)漫......
  • 软件测试3班,学员就业前的模拟面试(2019-9-12)(金朝阳)
    1:你用过Fiddler在项目中发现过哪些有价值的bug?2:接口测试,返回的数据格式类型一般有哪些类型?(Json\xml\html等等)3:App兼容性测试怎么做?APP升级测试怎么做?4:你测试过哪些类型的安卓机型?哪些类型的苹果机型?5:你测试过安卓机型的操作系统是多少?苹果机型的操作系统是多少?6:你在做接口测试的......
  • 软测5班Loadrunner阶段性考试(2019-10-19)
    试题1:用你在Loadrunner中所学习的知识,将“欢迎来到然学科技”保存为一个变量,并且在日志中打印输出(10分)。答案:lr_save_string("欢迎来到科技","ranther");lr_output_message("你好:%s",lr_eval_string("{ran}"));试题2:Loadrunner中如何保持每次参数取值的唯一性(2分)?Unique+Once(保持......
  • 软测5班jmeter笔记(2019-10-29)
    接口测试理论自动化测试的金字塔模型硬件接口:比如usb接口,电源接口、耳机接口...软件接口:数据系统访问接口、http请求接口...为什么要做接口测试Web前端:指用户可以直观操作和看到的界面。html,Css样式,javascript脚本。android和ios等。web后端:是指与数据库交互进行处理响应的业务......
  • P5288 [HNOI2019]多边形
    P5288[HNOI2019]多边形Solution先进行大量的模拟。最终所有线段的端点均为点\(n\)。第一问答案为\((n-1-与n相连的线段数量)\)。可以把线段看成节点,将原图转为若干棵二叉树组成的森林。这里只建那些不与点\(n\)相连的非边线段。原操作可以看作是sp......
  • P5333 [JSOI2019]神经网络
    P5333[JSOI2019]神经网络SolutionEGF表示有标号排列。对每棵树分别算出划分成\(i\)条链的方案数,记为\(f_i\)。具体地:设\(dp[u][i][0/1/2]\)表示在\(u\)子树内拆分成\(i\)条已结束的链,\(0\):已拼完,无法再延伸\(1\):单点,可继续向上扩展\(2\):长度\(>1\)的链......
  • word2019发布博客到博客园,解决word配置时出现的问题
    一开始按照网上的教程设置了博客URL,类似https://www.cnblogs.com/xxxxxxx/services/metaweblog.aspx这种,没有成功,再去查发现2021年之后就不支持这种URL地址了。改用设置-基本设置中的MetaWeblog访问地址,但还是提示word无法注册您的账户,也检查了用户名和密码就是登录时的用户名密......
  • 极客大挑战2019EasySQL
     如果不输入 随便输入 由地址栏的check.php?username=sadsad&password=sadsad可以猜测sql语句:$sql="select*fromxxwhereusername='$name'andpassword='$password'";既然是考sql注入,先试试万能密码用户名:’or1#密码随意判断是否正确的sql语句可能为:$sql="sel......