NOI-CSP/J 2024 T1:扑克牌 [PP11227]
前言
这是CSP/J 2024年第二轮 第一题。
📖
从【算法竞赛】角度这道题的解题思路,应该从【算法】角度入手。
然而,网络上的解题思路、教培机构教的方法、参赛选手等等,
——他们用的解题方法,基本都不是【算法】。
这道题,【正常情况下】考察的算法属于入门的基本算法:
排序
二分查找
不用算法的最简单解法:
只需要稍微熟悉 C++/STL 的常用类,用 set 或者 set_unsorted,甚至map/map_unsorted
——这些数据结构自动忽略重复数据,不需要排序、不需要二分查找,简单极了。
📖
一定会有些人振振有词:只要能得分,不用算法又如何?
——呵呵,您说的都对。
真实的软件开发工作中,这样的问题还真用不上算法。
但从【学习算法】的目的来说,我会要求我的孩子,必须用算法解答
——不偏离目的,不浪费时间。
当然,您安排孩子学编程的目的与我不同,所以您说的都对。
又有人要说了:第一题就是送分题。不用算法也能做出来,就对了。
——呵呵,您说的都对。
📖
《三体》中,一段很经典的情景:『人类不感谢罗辑』
昨天我大儿子给我讲了庄子说中井底之蛙的故事。
我告诉他现实中与故事中不同的地方:
——当你告诉井底之蛙,外面的世界很宽广,它不仅嘲笑你,还会帮那些把它当韭菜来收割的坏人攻击你。
它们的思维逻辑很奇怪,不是以【是否是事实】【是否合乎逻辑】来判断是非,
而是【假想你是羡慕它们,甚至认为你要害它们】。
——这恰恰正是它们为何会困在井底/认知茧房的原因。
人类为何不感谢罗辑?细节不展开,但恰恰是他们的认知与罗辑等人的认知不在一个层面。
原题
题目描述
📖
小 P 从同学小 Q 那儿借来一副 nn 张牌的扑克牌。
本题中我们不考虑大小王,此时每张牌具有两个属性:花色和点数。花色共有 44 种:方片、草花、红桃和黑桃。点数共有 1313 种,从小到大分别为 A23456789TJQKA23456789TJQK。注意:点数 1010 在本题中记为 TT。
我们称一副扑克牌是完整的,当且仅当对于每一种花色和每一种点数,都恰好有一张牌具有对应的花色和点数。由此,一副完整的扑克牌恰好有 4×13=524×13=52 张牌。以下图片展示了一副完整的扑克牌里所有的 52 张牌。
📖
小 P 借来的牌可能不是完整的,为此小 P 准备再向同学小 S 借若干张牌。可以认为小 S 每种牌都有无限张,因此小 P 可以任意选择借来的牌。小 P 想知道他至少得向小 S 借多少张牌,才能让从小 S 和小 Q 借来的牌中,可以选出 5252 张牌构成一副完整的扑克牌。
为了方便你的输入,我们使用字符 DD 代表方片,字符 CC 代表草花,字符 HH 代表红桃,字符 SS 代表黑桃,这样每张牌可以通过一个长度为 22 的字符串表示,其中第一个字符表示这张牌的花色,第二个字符表示这张牌的点数,例如 CACA 表示草花 AA,STST 表示黑桃 TT(黑桃 10)。
输入格式
输入的第一行包含一个整数 nn 表示牌数。
接下来 nn 行:
每行包含一个长度为 22 的字符串描述一张牌,其中第一个字符描述其花色,第二个字符描述其点数。
输出格式
输出一行一个整数,表示最少还需要向小 S 借几张牌才能凑成一副完整的扑克牌。
输入输出样例
📖
输入 #1
1
SA
📖
输出 #1
51
📖
输入 #2
4
DQ
H3
DQ
DT
📖
输出 #2
49
说明/提示
📖
【样例 1 解释】
这一副牌中包含一张黑桃 AA,小 P 还需要借除了黑桃 AA 以外的 51 张牌以构成一副完整的扑克牌。
📖
【样例 2 解释】
这一副牌中包含两张方片 QQ、一张方片 TT(方片 10)以及一张红桃 3,小 P 还需要借除了红桃 3、方片 TT 和方片 QQ 以外的 4949 张牌。
📖
【样例 3 解释】
见选手目录下的 poker/poker3.in 与 poker/poker3.ans。
这一副扑克牌是完整的,故不需要再借任何牌。
该样例满足所有牌按照点数从小到大依次输入,点数相同时按照方片、草花、红桃、黑桃的顺序依次输入。
📖
【数据范围】
对于所有测试数据,保证:1≤n≤521≤n≤52,输入的 nn 个字符串每个都代表一张合法的扑克牌,即字符串长度为 22,且第一个字符为 DCHSDCHS 中的某个字符,第二个字符为 A23456789TJQKA23456789TJQK 中的某个字符。
📖
特殊性质 A:保证输入的 nn 张牌两两不同。
特殊性质 B:保证所有牌按照点数从小到大依次输入,点数相同时按照方片、草花、红桃、黑桃的顺序依次输入。
解题
不用算法取巧——不鼓励
#include <bits/stdc++.h>
using namespace std;
int main()
{
unordered_set<string> cards;
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
string card;
cin >> card;
if (cards.find(card) != cards.end())
{
cards.emplace(card);
}
}
cout << 52 - cards.size() << endl;
return 0;
}
二分法
待续