A - 咕咕东的目录管理器
题意
解题思路
- 首先我们要确定如何存储目录以及子目录,因为题目要求子目录必须要保持字典序,所以我们选用map来存储一个目录的所有子目录。
- MKDIR:直接在当前目录的map里插入新的目录即可。
- RM:是MKDIR的逆操作,将要删除的目录从当前目录中擦除即可。
- CD:将当前目录改为新目录
- SZ:每一次都遍历子目录会超时,所以我们可以对每一个目录增加sz来表示该目录的子节点数,这时,就需要在MKDIR和RM时向上更新sz直到root
- LS:直接判断并按顺序输出map的元素即可。
- TREE:与SZ类似,每一次都遍历的话会超时,所以我们可以存储一下答案,并标记一下是否被更新过。若进行了MKDIR和RM,则标记置空。
- UNDO:我们可以用一个vector存储执行过的指令,然后执行其逆操作即可。(在RM时我们不需要删除对应目录的所有信息,只需删去关系,以便恢复)
代码
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
map<string, int> cases = {
{"MKDIR", 0}, {"RM", 1}, {"CD", 2},
{"SZ", 3}, {"LS", 4},{"TREE", 5},{"UNDO", 6}
};
struct command{
int code;
int op1;
int op2;
command(int a, int b, int c): code(a), op1(b), op2(c){}
};
vector<command> cmd;
int now;
struct Directory
{
string name;
map<string, int> mp;
int fa, sz;
vector<string> pre,bck;
bool tag;
}node[100005];
int node_i;
void update(int id, int num){
while(id != -1){
node[id].tag = 0;
node[id].sz += num;
id = node[id].fa;
}
}
void mkdir(string &str){
if(node[now].mp.count(str)){
cout << "ERR\n";
return;
}
cout << "OK\n";
update(now, 1);
node[now].mp.insert(pair<string, int>(str, node_i));
node[node_i].name = str;
node[node_i].fa = now;
node[node_i].sz = 1;
node[node_i].pre.clear();
node[node_i].bck.clear();
node[node_i].mp.clear();
node[node_i].tag = 0;
command temp(0, now, node_i++);
cmd.push_back(temp);
}
void rm(string &str){
if(!node[now].mp.count(str)){
cout << "ERR\n";
return;
}
cout << "OK\n";
int temps = node[now].mp[str];
node[now].mp.erase(str);
update(now, -node[temps].sz);
command temp(1, now, temps);
cmd.push_back(temp);
}
void cd(string &str){
if(str == ".."){
if(now == 0)
cout << "ERR\n";
else{
int tmpn = now;
now = node[now].fa;
cout << "OK\n";
command temp(2, tmpn, now);
cmd.push_back(temp);
}
}else{
if(node[now].mp.count(str)){
int tmpn = now;
now = node[now].mp[str];
cout << "OK\n";
command temp(2, tmpn, now);
cmd.push_back(temp);
}else
cout << "ERR\n";
}
}
void ls(){
int t = node[now].mp.size();
if(t == 0)
cout << "EMPTY\n";
else if(t >= 1 && t <= 10)
for(auto cur = node[now].mp.begin(); cur != node[now].mp.end(); cur++)
cout << cur->first << endl;
else{
auto cur = node[now].mp.begin();
for(int i = 0; i < 5; i++){
cout << cur->first << endl;
cur++;
}
cout << "...\n";
cur = node[now].mp.end();
for(int i = 0; i < 5; i++) cur--;
for(int i = 0; i < 5; i++){
cout << cur->first << endl;
cur++;
}
}
}
void undo(){
if(!cmd.size()){
cout << "ERR\n";
return;
}
cout << "OK\n";
command c = cmd[cmd.size()-1];
cmd.pop_back();
switch(c.code){
case 0:
update(c.op1, -node[c.op2].sz);
node[c.op1].mp.erase(node[c.op2].name);
break;
case 1:
update(c.op1, node[c.op2].sz);
node[c.op1].mp[node[c.op2].name] = c.op2;
case 2:
now = c.op1;
}
}
void pretrack(int id, int& t){
node[now].pre.push_back(node[id].name);
if(t-- == 0) return;
for(auto cur = node[id].mp.begin(); cur != node[id].mp.end(); cur++){
pretrack(cur->second, t);
if(t == 0) break;
}
}
void pretrack(){
int t;
if(node[now].sz > 10) t = 5;
else t = node[now].sz;
pretrack(now, t);
}
void bcktrack(int id, int& t){
auto cur = node[id].mp.end();
int SIZE = node[id].mp.size();
for(int i = 0; i < SIZE; i++){
cur--;
bcktrack(cur->second, t);
if(t == 0) return;
}
node[now].bck.push_back(node[id].name);
t--;
}
void pushdown(){
node[now].pre.clear();
node[now].bck.clear();
pretrack();
if(node[now].sz > 10) {
int t = 5;
bcktrack(now, t);
}
else node[now].bck = node[now].pre;
node[now].tag = 1;
}
void tree(){
if(!node[now].tag) pushdown();
if(node[now].sz == 1) cout << "EMPTY\n";
else if(node[now].sz > 1 && node[now].sz <= 10)
for(int i = 0; i < node[now].pre.size(); i++)
cout << node[now].pre[i] << endl;
else{
for(int i = 0; i <5; i++) cout << node[now].pre[i] << endl;
cout << "...\n";
for(int i = 4; i >= 0; i--) cout <<node[now].bck[i] << endl;
}
}
int main(){
int T;
cin >> T;
while(T--){
cmd.clear();
node_i = 1;
now = 0;
node[0].name = "root";
node[0].fa = -1;
node[0].sz = 1;
node[0].tag = 0;
node[0].pre.clear();
node[0].bck.clear();
node[0].mp.clear();
int Q;
cin >> Q;
while(Q--){
string cmmd;
cin >> cmmd;
switch(cases[cmmd]){
case 0:{
string str;
cin >> str;
mkdir(str);
break;
}
case 1:{
string str;
cin >> str;
rm(str);
break;
}
case 2:{
string str;
cin >> str;
cd(str);
break;
}
case 3:{
cout << node[now].sz << endl;
break;
}
case 4:{
ls();
break;
}
case 5:{
tree();
break;
}
case 6:{
undo();
break;
}
}
}
cout << "\n";
}
return 0;
}
B - 东东学打牌
题意
最近,东东沉迷于打牌。所以他找到 HRZ、ZJM 等人和他一起打牌。由于人数众多,东东稍微修改了亿下游戏规则:
- 所有扑克牌只按数字来算大小,忽略花色。
- 每张扑克牌的大小由一个值表示。A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K 分- 别指代 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13。
- 每个玩家抽得 5 张扑克牌,组成一手牌!(每种扑克牌的张数是无限的,你不用担心,东东家里有无数副扑克牌)
理所当然地,一手牌是有不同类型,并且有大小之分的。
举个栗子,现在东东的 “一手牌”(记为 α),瑞神的 “一手牌”(记为 β),要么 α > β,要么 α < β,要么 α = β。
那么这两个 “一手牌”,如何进行比较大小呢?首先对于不同类型的一手牌,其值的大小即下面的标号;对于同类型的一手牌,根据组成这手牌的 5 张牌不同,其值不同。下面依次列举了这手牌的形成规则:
- 大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。
- 对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。
- 两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。
- 三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。
- 三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。
- 炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。
- 顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。
- 龙顺:5 张牌分别为 10、J、Q、K、A。
作为一个称职的魔法师,东东得知了全场人手里 5 张牌的情况。他现在要输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。
不料,此时一束宇宙射线扫过,为了躲避宇宙射线,东东慌乱中清空了他脑中的 Cache。请你告诉东东,全场人的排名
解题思路
一道操作较多但都比较简单的模拟题,和这道题较为类似。
首先读入每位玩家的姓名和牌,将牌转换成int数组存储,之后计算i张相同牌的数量为cnt[i],并将牌面存入对应的cnt1[i]中,之后就能较为方便的判断牌属于哪个牌型。
代码
#include <iostream>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
struct player{
string name;
int card[6];
int cnt[6];
vector<int> cnt1[6];
int point;
void count(){
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < 6; i++)
cnt1[i].clear();
int last = card[0];
int k = 1;
for(int i = 1; i < 5; i++){
if(card[i] == last)
k++;
else{
cnt[k]++;
cnt1[k].push_back(last);
k = 1;
last = card[i];
}
}
cnt[k]++;
cnt1[k].push_back(last);
}
void cal(){
count();
if(card[0] == 1 && card[1] == 10 && card[2] == 11 && card[3] == 12 && card[4] == 13)
point = 8;
else if(card[1] == card[0] + 1 && card[2] == card[1] + 1 && card[3] == card[2] + 1 && card[4] == card[3] + 1)
point = 7;
else if(cnt[4] == 1)
point = 6;
else if(cnt[3] == 1 && cnt[2] == 1)
point = 5;
else if(cnt[3] == 1)
point = 4;
else if(cnt[2] == 2)
point = 3;
else if(cnt[2] == 1)
point = 2;
else
point = 1;
}
}p[100005];
map<char, int>mp{{'K', 13}, {'Q', 12}, {'J', 11}, {'A', 1}, {'2', 2}, {'3', 3}, {'4', 4}, {'5', 5}, {'6', 6}, {'7', 7}, {'8', 8}, {'9', 9}};
bool cmp(player &a, player &b){
if(a.point != b.point)
return a.point > b.point;
else{
int sum1 = 0, sum2 = 0;
for(int i = 0; i < a.cnt1[1].size(); i++){
sum1 += a.cnt1[1][i];
sum2 += b.cnt1[1][i];
}
if(a.point == 8)
return a.name < b.name;
else if(a.point == 7){
if(a.card[2] != b.card[2])
return a.card[2] > b.card[2];
else
return a.name < b.name;
}else if(a.point == 6){
if(a.card[2] != b.card[2])
return a.card[1] > b.card[1];
else if(a.cnt1[1][0] != b.cnt1[1][0])
return a.cnt1[1][0] > b.cnt1[1][0];
else
return a.name < b.name;
}
else if(a.point == 5){
if(a.card[2] != b.card[2])
return a.card[2] > b.card[2];
else{
if(a.cnt1[2][0] != b.cnt1[2][0])
return a.cnt1[2][0] > b.cnt1[2][0];
else
return a.name < b.name;
}
}else if(a.point == 4){
if(a.card[2] != b.card[2])
return a.card[2] > b.card[2];
else{
if(sum1 != sum2)
return sum1 > sum2;
else
return a.name < b.name;
}
}else if(a.point == 3){
if(a.card[3] != b.card[3])
return a.card[3] > b.card[3];
else if(a.card[1] != b.card[1])
return a.card[1] > b.card[1];
else if(a.cnt1[1][0] != b.cnt1[1][0])
return a.cnt1[1][0] > b.cnt1[1][0];
else
return a.name < b.name;
}else if(a.point == 2){
if(a.cnt1[2][0] != b.cnt1[2][0])
return a.cnt1[2][0] > b.cnt1[2][0];
else if(sum1 != sum2)
return sum1 > sum2;
else
return a.name < b.name;
}else{
if(sum1 != sum2)
return sum1 > sum2;
else
return a.name < b.name;
}
}
}
int main()
{
int n;
while(cin >> n){
for(int i = 0; i < n; i++){
string str;
cin >> p[i].name >> str;
int k = 0;
for(int j = 0; j < str.length(); j++){
if(str[j] == '1'){
p[i].card[k++] = 10;
j++;
}else
p[i].card[k++] = mp[str[j]];
}
sort(p[i].card, p[i].card + 5);
p[i].cal();
}
sort(p, p + n, cmp);
for(int i = 0; i < n; i++)
cout << p[i].name << endl;
}
return 0;
}
C - 签到题
题意
SDUQD 旁边的滨海公园有 x 条长凳。第 i 个长凳上坐着 a_i 个人。这时候又有 y 个人将来到公园,他们将选择坐在某些公园中的长凳上,那么当这 y 个人坐下后,记k = 所有椅子上的人数的最大值,那么k可能的最大值mx和最小值mn分别是多少。
解题思路
- 因为没有规定一个凳子能坐多少人,mx的值很容易想到,y个人全部都坐到原来人数最多的凳子上即可,所以我们在读入每个凳子上人数的时候比较记录最大值,最后
m
x
=
y
+
m
a
x
(
a
i
)
mx = y + max(a_i)
mx=y+max(ai)
- mn的取值分为两种情况:
- 当
s
u
m
(
a
i
)
+
y
≤
x
⋅
m
a
x
(
a
i
)
sum(a_i)+y \leq x \cdot max(a_i)
sum(ai)+y≤x⋅max(ai)时,我们可以把y个人分配到人数最多的长凳之外的长凳上,如果优先从人数少的长凳开始分配,则最后人数最多的长凳上的人数依然为
m
a
x
(
a
i
)
max(a_i)
max(ai).
- 当
s
u
m
(
a
i
)
+
y
>
x
⋅
m
a
x
(
a
i
)
sum(a_i)+y > x \cdot max(a_i)
sum(ai)+y>x⋅max(ai)时,我们将所有人平均分配到x个长凳上,平均值即为mn(这里要注意如果
s
u
m
(
a
i
)
+
y
sum(a_i)+y
sum(ai)+y不能被x整除,得到的结果要+1)
代码
#include <iostream>
using namespace std;
int main()
{
int x, y;
cin >> x >> y;
int maxx = 0;
int sum = 0;
for (int i = 0; i < x; i++) {
int temp;
cin >> temp;
if (temp > maxx)
maxx = temp;
sum += temp;
}
if (sum + y > maxx * x) {
if ((sum + y) % x == 0)
cout << (sum + y) / x;
else
cout << (sum + y) / x + 1;
} else
cout << maxx;
cout << ' ';
cout << maxx + y;
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)