A - 咕咕东的目录管理器
题目
sample input
1
22
MKDIR dira
CD dirb
CD dira
MKDIR a
MKDIR b
MKDIR c
CD ..
MKDIR dirb
CD dirb
MKDIR x
CD ..
MKDIR dirc
CD dirc
MKDIR y
CD ..
SZ
LS
TREE
RM dira
TREE
UNDO
TREE
sample output
OK
ERR
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
9
dira
dirb
dirc
root
dira
a
b
c
dirb
x
dirc
y
OK
root
dirb
x
dirc
y
OK
root
dira
a
b
c
dirb
x
dirc
y
解题思路
用数组存储目录树,记录父结点和叶结点;
创建目录更新递推一直更新到root;
进入目录要考虑是回到上层目录还是到下层目录,同时要记录历史记录,undo要取出最近的一次操作,并执行相反操作回到上一个状态;
tree操作是最麻烦的,每次要查询时先判断当前存储的答案是不是更新后的,如果不是就更新答案,否则直接输出。
这一题就是很麻烦很麻烦很麻烦很烦不好理清问了好多人看了好多写法
完整代码
#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;
struct Node
{
string dirname;
int fa;
map<string, int> cld;
int size;
vector<string> p5, b5;
bool tag;
};
struct rec
{
string ml;
string dirname;
int d;
};
int curr_node, cnt;
vector<rec> record;
Node dtree[100000];
void update(int num)
{
int temp = curr_node;
while(temp != -1)
{
dtree[temp].tag = false;
dtree[temp].size += num;
temp = dtree[temp].fa;
}
}
void mkdir(string s)
{
if(dtree[curr_node].cld.find(s) != dtree[curr_node].cld.end())
{
cout << "ERR" << endl;
return;
}
Node nn;
nn.dirname = s;
nn.fa = curr_node;
nn.size = 1;
nn.tag = false;
nn.cld.clear();
nn.p5.clear();
nn.b5.clear();
dtree[cnt] = nn;
cout << "OK" << endl;
rec rr;
rr.ml = "mkdir";
rr.dirname = s;
rr.d = cnt;
record.push_back(rr);
dtree[curr_node].cld[s] = cnt++; update(1);
}
void rm(string s)
{
if(dtree[curr_node].cld.find(s) == dtree[curr_node].cld.end())
{
cout << "ERR" << endl;
return;
}
int num = dtree[curr_node].cld.find(s)->second;
cout << "OK" <<endl;
rec rr;
rr.ml = "rm";
rr.dirname = s;
rr.d = num;
record.push_back(rr);
dtree[curr_node].cld.erase(s); update(-1*dtree[num].size);
}
void cd(string s)
{
if(s == "..")
{
int fa = dtree[curr_node].fa;
if(fa == -1)
{
cout << "ERR" <<endl;
return;
}
else
{
cout << "OK"<<endl;
rec rr;
rr.ml = "cd";
rr.dirname = s;
rr.d = curr_node;
record.push_back(rr);
curr_node = dtree[curr_node].fa;
return;
}
}
if(dtree[curr_node].cld.find(s) == dtree[curr_node].cld.end())
{
cout << "ERR"<<endl;
return;
}
cout << "OK"<<endl;
rec rr;
rr.ml = "cd";
rr.dirname = s;
rr.d = curr_node;
record.push_back(rr);
curr_node = dtree[curr_node].cld.find(s)->second;
}
void ls(int d)
{
int len = dtree[d].cld.size();
if(len == 0)
{
cout << "EMPTY"<<endl;
return;
}
if(len <= 10)
{
for(map<string, int>::iterator it = dtree[d].cld.begin(); it != dtree[d].cld.end(); it++)
{
cout << dtree[it->second].dirname << endl;
}
return;
}
map<string, int>::iterator it = dtree[d].cld.begin();
for(int i = 0; i < 5; ++i)
{
cout << dtree[it->second].dirname << endl; it++;
}
cout << "...\n";
it = dtree[d].cld.end();
for(int i = 0; i < 5; ++i) it--;
for(int i = 0; i < 5; ++i)
{
cout << dtree[it->second].dirname << endl; it++;
}
return;
}
void fser(int d, vector<string>& v)
{
v.push_back(dtree[d].dirname);
int len = dtree[d].cld.size();
for(map<string, int>::iterator it = dtree[d].cld.begin(); it != dtree[d].cld.end(); it++)
{
fser(it->second, v);
}
}
void p_d(int d)
{
dtree[d].p5.clear(); dtree[d].b5.clear();
fser(d, dtree[d].p5);
dtree[d].tag = true;
}
void tt_p(int num, int d, vector<string>& v)
{
v.push_back(dtree[d].dirname);
if(--num == 0)
return;
int len = dtree[d].cld.size();
for(map<string, int>::iterator it = dtree[d].cld.begin(); it != dtree[d].cld.end(); it++)
{
int csize = dtree[it->second].size;
if(csize >= num)
{
tt_p(num, it->second, v);
return;
}
else
{
tt_p(csize, it->second, v);
num -= csize;
}
}
}
void tt_a(int num, int d, vector<string>& v)
{
int len = dtree[d].cld.size();
map<string, int>::iterator it = dtree[d].cld.end();
while(len--)
{
it--;
int csize = dtree[it->second].size;
if(csize >= num)
{
tt_a(num, it->second, v);
return;
}
else
{
tt_a(csize, it->second, v);
num -= csize;
}
}
v.push_back(dtree[d].dirname);
}
void search_t(int d)
{
if(dtree[d].size == 1)
{
cout << "EMPTY" << endl;
}
else if(dtree[d].size > 1 && dtree[d].size <= 10)
{
if(!dtree[d].tag)
{
p_d(d);
}
for(int i = 0, len = dtree[d].p5.size(); i < len; ++i)
{
cout << dtree[d].p5[i] << endl;
}
}
else if(dtree[d].size > 10)
{
if(!dtree[d].tag)
{
dtree[d].p5.clear(); dtree[d].b5.clear();
tt_p(5, d, dtree[d].p5);
tt_a(5, d, dtree[d].b5);
dtree[d].tag = true;
}
for(int i = 0; i < 5; ++i)
{
cout << dtree[d].p5[i] << endl;
}
cout << "..."<<endl;
for(int i = 4; i >= 0; --i)
{
cout << dtree[d].b5[i] << endl;
}
}
}
void undo()
{
int len = record.size();
if(len == 0)
{
cout << "ERR" << endl;
return;
}
string ml = record[len-1].ml;
cout << "OK" << endl;
record.pop_back();
if(ml == "mkdir")
{
int goal = record[len-1].d;
string s = record[len-1].dirname;
dtree[curr_node].cld.erase(s);
update(-1*dtree[goal].size);
}
else if(ml == "rm")
{
int goal = record[len-1].d;
string s = record[len-1].dirname;
dtree[curr_node].cld[s] = goal;
update(1*dtree[goal].size);
}
else if(ml == "cd")
{
curr_node = record[len-1].d;
}
}
int main()
{
int t; cin >> t;
while(t--)
{
int q; cin >> q;
curr_node = 0, cnt = 1;
record.clear();
Node nn;
nn.dirname = "root";
nn.fa = -1;
nn.size = 1;
nn.tag = false;
nn.cld.clear();
nn.p5.clear();
nn.b5.clear();
dtree[curr_node] = nn;
for(int cas = 1; cas <= q; cas++)
{
string ml;
cin >> ml;
if(ml=="MKDIR")
{
string s;
cin >> s;
mkdir(s);
continue;
}
if(ml=="RM")
{
string s;
cin >> s;
rm(s);
continue;
}
if(ml=="CD")
{
string s;
cin >> s;
cd(s);
continue;
}
if(ml=="SZ")
{
cout << dtree[curr_node].size << endl;
continue;
}
if(ml=="LS")
{
ls(curr_node);
continue;
}
if(ml=="TREE")
{
search_t(curr_node);
continue;
}
if(ml=="UNDO")
{
undo();
continue;
}
}
}
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。请你告诉东东,全场人的排名
输入
输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。
输出
对于每组测试数据,输出 n 行,即这次全场人的排名。
样例输入
3
DongDong AAA109
ZJM 678910
Hrz 678910
样例输出
Hrz
ZJM
DongDong
解题思路
一个看起来很复杂的大模拟,其实不难,判断牌型很简单,主要部分还是在比较排序上。在定义结构体的时候,除了存储姓名和牌以外,用变量记录四层判断以此排序。
还有在判断牌型的时候,要注意牌型之间的包含关系,从后往前判断才行。
完整代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n;
string num;
int cnt;
struct player
{
string name;
int card[5];
int a, b, c, d;
bool operator < (const player x) const
{
if(a != x.a )
{
return a > x.a;
}
if(b != x.b )
{
return b > x.b;
}
if(c != x.c )
{
return c > x.c;
}
if(d != x.d )
{
return d > x.d;
}
return name < x.name;
}
}s[100010];
void Sort(int x)
{
if(s[x].card[0] == 1 && s[x].card[1] == 10 && s[x].card[2] == 11 && s[x].card[3] == 12 && s[x].card[4] == 13)
{
s[x].a = 8;
s[x].b = 0;
s[x].c = 0;
s[x].d = 0;
}
else if(s[x].card[0]+1 == s[x].card[1] && s[x].card[1]+1 == s[x].card[2] && s[x].card[2]+1 == s[x].card[3] && s[x].card[3]+1 == s[x].card[4])
{
s[x].a = 7;
s[x].b = s[x].card[4];
s[x].c = 0;
s[x].d = 0;
}
else if(s[x].card[0] == s[x].card[1] && s[x].card[1] == s[x].card[2] && s[x].card[2] == s[x].card[3])
{
s[x].a = 6;
s[x].b = s[x].card[0];
s[x].c = s[x].card[4];
s[x].d = 0;
}
else if(s[x].card[1] == s[x].card[2] && s[x].card[2] == s[x].card[3] && s[x].card[3] == s[x].card[4])
{
s[x].a = 6;
s[x].b = s[x].card[1];
s[x].c = s[x].card[0];
s[x].d = 0;
}
else if(s[x].card[0] == s[x].card[1] && s[x].card[1] == s[x].card[2] && s[x].card[3] == s[x].card[4])
{
s[x].a = 5;
s[x].b = s[x].card[0];
s[x].c = s[x].card[3];
s[x].d = 0;
}
else if(s[x].card[0] == s[x].card[1] && s[x].card[2] == s[x].card[3] && s[x].card[3] == s[x].card[4])
{
s[x].a = 5;
s[x].b = s[x].card[2];
s[x].c = s[x].card[0];
s[x].d = 0;
}
else if(s[x].card[0] == s[x].card[1] && s[x].card[1] == s[x].card[2])
{
s[x].a = 4;
s[x].b = s[x].card[0];
s[x].c = s[x].card[3] + s[x].card[4];
s[x].d = 0;
}
else if(s[x].card[1] == s[x].card[2] && s[x].card[2] == s[x].card[3])
{
s[x].a = 4;
s[x].b = s[x].card[1];
s[x].c = s[x].card[0] + s[x].card[4];
s[x].d = 0;
}
else if(s[x].card[2] == s[x].card[3] && s[x].card[3] == s[x].card[4])
{
s[x].a = 4;
s[x].b = s[x].card[2];
s[x].c = s[x].card[0] + s[x].card[1];
s[x].d = 0;
}
else if(s[x].card[0] == s[x].card[1] && s[x].card[2] == s[x].card[3])
{
s[x].a = 3;
s[x].b = s[x].card[2];
s[x].c = s[x].card[0];
s[x].d = s[x].card[4];
}
else if(s[x].card[0] == s[x].card[1] && s[x].card[4] == s[x].card[3])
{
s[x].a = 3;
s[x].b = s[x].card[3];
s[x].c = s[x].card[0];
s[x].d = s[x].card[2];
}
else if(s[x].card[1] == s[x].card[2] && s[x].card[3] == s[x].card[4])
{
s[x].a = 3;
s[x].b = s[x].card[3];
s[x].c = s[x].card[1];
s[x].d = s[x].card[0];
}
else if(s[x].card[0] == s[x].card[1])
{
s[x].a = 2;
s[x].b = s[x].card[0];
s[x].c = s[x].card[2] + s[x].card[3] + s[x].card[4];
s[x].d = 0;
}
else if(s[x].card[1] == s[x].card[2])
{
s[x].a = 2;
s[x].b = s[x].card[1];
s[x].c = s[x].card[0]+s[x].card[3]+s[x].card[4];
s[x].d = 0;
}
else if(s[x].card[2] == s[x].card[3])
{
s[x].a = 2;
s[x].b = s[x].card[2];
s[x].c = s[x].card[0] + s[x].card[1] + s[x].card[4];
s[x].d = 0;
}
else if(s[x].card[3] == s[x].card[4])
{
s[x].a = 2;
s[x].b = s[x].card[3];
s[x].c = s[x].card[0] + s[x].card[1] + s[x].card[2];
s[x].d = 0;
}
else
{
s[x].a = 1;
s[x].b = s[x].card[0]+s[x].card[1]+s[x].card[2]+s[x].card[3]+s[x].card[4];
s[x].c = 0;
s[x].d = 0;
}
}
int main()
{
while(scanf("%d",&n) != EOF)
{
for(int i=1;i<=n;i++)
{
cnt = 0;
cin>>s[i].name>>num;
for(int j = 0;j<num.length();j++)
{
if(num[j] == 'A')
{
s[i].card[cnt++] = 1;
}
else if(num[j] >= '2' && num[j] <= '9')
{
s[i].card[cnt++] = num[j] - '0';
}
else if(num[j] == '1')
{
s[i].card[cnt++] = 10;
j++;
}
else if(num[j] == 'J')
{
s[i].card[cnt++] = 11;
}
else if(num[j] == 'Q')
{
s[i].card[cnt++] = 12;
}
else if(num[j] == 'K')
{
s[i].card[cnt++] = 13;
}
}
sort(s[i].card, s[i].card + 5);
Sort(i);
}
sort(s+1, s+1+n);
for(int i=1;i<=n;i++) cout<<s[i].name<<endl;
}
return 0;
}
C - 长凳
题目
SDUQD 旁边的滨海公园有 x 条长凳。第 i 个长凳上坐着 a_i 个人。这时候又有 y 个人将来到公园,他们将选择坐在某些公园中的长凳上,那么当这 y 个人坐下后,记k = 所有椅子上的人数的最大值,那么k可能的最大值mx和最小值mn分别是多少。
Input
第一行包含一个整数 x (1 <= x <= 100) 表示公园中长椅的数目
第二行包含一个整数 y (1 <= y <= 1000) 表示有 y 个人来到公园
接下来 x 个整数 a_i (1<=a_i<=100),表示初始时公园长椅上坐着的人数
Output
输出 mn 和 mx
样例
Input Example
3
7
1
6
1
Output Example
6 13
样例解释
最初三张椅子的人数分别为 1 6 1
接下来来了7个人。
可能出现的情况为{1 6 8},{1,7,7},…,{8,6,1}
相对应的k分别为8,7,…,8
其中,状态{1,13,1}的k = 13,为mx
状态{4,6,5}和状态{5,6,4}的k = 6,为mn
解题思路
最大值mx很好求,将数组排序,在原来最大的基础上直接加k就行了。
最小值mn:因为最开始的最大值是a[n],所以mn一定会>=a[n];
首先,用k个人去补齐前面n-1个长凳,让他们都为a[n],如果k个人没法补齐,说明最大值还是a[n];
如果还剩余了kk个人,就把这kk个人均分到n个长凳上,如果恰好均分,就是a[n]+kk/n,如果不能均分,就是a[n]+kk/n+1.
完整代码
#include<iostream>
#include<algorithm>
using namespace std;
int n, k, t = 0;
int a[110];
int mx, mn;
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1, a+n+1);
mx = a[n] + k;
for(int i=1;i<n;i++) t = t + (a[n] - a[i]);
if(t >= k) mn = a[n];
else
{
k -= t;
if(k % n == 0) mn = a[n] + (k/n);
else mn = a[n] + (k/n) + 1;
}
cout<<mn<<' '<<mx;
return 0;
}