第一题
题意
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!
初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
现在咕咕东可以在命令行下执行以下表格中描述的命令:
输入
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。
输出
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。
时空限制
Time limit 6000 ms
Memory limit 1048576 kB
思路
对于一组数据:
设置结构体cmd用来存储指令,包括指令类型,进行操作的目录s,位置olddir。
设置结构体dir用来存储节点,包括当前节点名字,父节点,子节点的map映射,以当前为根的子树的大小,更新标记,遍历数组,各种函数。
对于undo命令,因为要进行撤销,所以我们要对所有能执行的命令进行储存。
代码
#include<iostream>
#include<map>
#include<vector>
using namespace std;
string commands[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
struct dir
{
string name;
map<string,dir*> children;
dir *parent;
int size;
bool update;
vector<string> ans;
dir (string name,dir *parent)
{
size=1;
this->name=name;
this->parent=parent;
}
public:
dir* getchild(string s)
{
map<string,dir*>::iterator it=children.find(s);
if (it==children.end())
return NULL;
return it->second;
}
dir* mkdir(string s)
{
if (children.find(s)!=children.end())
return NULL;
dir *now=new dir(s,this);
children[s]=now;
maintain(1);
return now;
}
dir* rm(string s)
{
map<string,dir*>::iterator it=children.find(s);
if (it==children.end())
return NULL;
maintain(-it->second->size);
children.erase(it);
return it->second;
}
dir* cd(string s)
{
if (s=="..")
return this->parent;
return getchild(s);
}
void addchild(dir *child)
{
if (children.find(child->name)!=children.end())
return;
children[child->name]=child;
maintain(child->size);
return;
}
void maintain(int sum)
{
update=true;
size=size+sum;
if (parent!=NULL)
parent->maintain(sum);
}
void sz()
{
cout<<size<<endl;
}
void ls()
{
int sum=children.size();
if (sum==0)
{
cout<<"EMPTY"<<endl;
return;
}
if (sum<=10)
{
map<string,dir*>::iterator it=children.begin();
while (it!=children.end())
{
cout<<it->first<<endl;
it++;
}
}
else
{
map<string,dir*>::iterator it=children.begin();
for (int i=0;i<5;i++)
{
cout<<it->first<<endl;
it++;
}
cout<<"..."<<endl;
it=children.end();
for (int i=0;i<5;i++)
it--;
for (int i=0;i<5;i++)
{
cout<<it->first<<endl;
it++;
}
}
}
void tree()
{
if (size==1)
{
cout<<"EMPTY"<<endl;
return;
}
if(size<=10)
{
if (update) //需要更新则更新
{
ans.clear();
treeall(&ans);
update=false;
}
for(int i=0;i<size;i++)
cout<<ans[i]<<endl;
}
else
{
if (update)
{
ans.clear();
treel(5,&ans);
treer(5,&ans);
update=false;
}
for(int i=0;i<5;i++)
cout<<ans[i]<<endl;
cout<<"..."<<endl;
for(int i=9;i>=5;i--)
cout<<ans[i]<<endl;
}
}
private:
void treeall(vector<string> *v)
{
v->push_back(name);
map<string,dir*>::iterator it=children.begin();
while (it!=children.end())
{
it->second->treeall(v);
it++;
}
}
void treel(int x,vector<string> *v)
{
v->push_back(name);
x--;
if (x==0)
return;
int n=children.size();
map<string,dir*>::iterator it=children.begin();
while (n--)
{
int sum=it->second->size;
if (sum>=x)
{
it->second->treel(x,v);
return;
}
else
{
it->second->treel(sum,v);
x=x-sum;
}
it++;
}
}
void treer(int x,vector<string> *v)
{
int n=children.size();
map<string,dir*>::iterator it=children.end();
while (n--)
{
it--;
int sum=it->second->size;
if (sum>=x)
{
it->second->treer(x,v);
return;
}
else
{
it->second->treer(sum,v);
x=x-sum;
}
}
v->push_back(name);
}
};
struct cmd
{
int type;
string s;
dir* olddir;
cmd(string temp)
{
for(int i=0;i<7;i++)
if(commands[i]==temp)
{
type=i;
if (i<3)
cin>>s;
}
}
};
void solve()
{
dir *now=new dir("root",NULL);
vector<cmd*> cmdlist;
string s;
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>s;
cmd *c=new cmd(s);
if (c->type==0)
{
c->olddir=now->mkdir(c->s);
if (c->olddir==NULL)
cout<<"ERR"<<endl;
else
{
cout<<"OK"<<endl;
cmdlist.push_back(c);
}
}
if (c->type==1)
{
c->olddir=now->rm(c->s);
if(c->olddir==NULL)
cout<<"ERR"<<endl;
else
{
cout<<"OK"<<endl;
cmdlist.push_back(c);
}
}
if (c->type==2)
{
dir *newNow=now->cd(c->s);
if (newNow==NULL)
cout<<"ERR"<<endl;
else
{
cout<<"OK"<<endl;
c->olddir=now;
now=newNow;
cmdlist.push_back(c);
}
}
if (c->type==3)
now->sz();
if (c->type==4)
now->ls();
if (c->type==5)
now->tree();
if (c->type==6)
{
if (!cmdlist.empty())
{
c=cmdlist.back();
if (c->type==0)
dir *temp=now->rm(c->s);
if (c->type==1)
now->addchild(c->olddir);
if (c->type==2)
now=c->olddir;
cout<<"OK"<<endl;
}
else
cout<<"ERR"<<endl;
}
}
}
int main()
{
int t;
cin>>t;
for(int i=0;i<t;i++)
solve();
return 0;
}
第二题
题意
最近,东东沉迷于打牌。所以他找到 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 行,即这次全场人的排名。
思路
比较大小,一共只有八种情况,所以我们直接处理手牌是哪种情况,设第x种,然后给这个手牌一个权重,首先设置一个大数,1e7,然后权重就是1e7x,然后对于同一种手牌,我们的比较最多也只用三次比较,所以第一次10000+第二次*100+第三次构成我们只一种手牌的权重。
举个例子,4499K,首先这是两对,属于第三种,sum=1e73+910000+4*100+13,这样我们对所有的手牌处理之后直接sort,逆序输出即可。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define ll 10000000
using namespace std;
struct data
{
string name;
int sum;
bool operator < (const data & x)
{
return (sum!=x.sum)?(sum<x.sum):(name>x.name);
}
};
int main()
{
int n,o,tot;
string s;
data a[100010];
int p[100];
int x[100],y[100];
while (scanf("%d",&n)!=EOF)
{
for (int j=0;j<n;j++)
{
cin>>a[j].name;
cin>>s;
int l=s.length();
for (int i=0;i<20;i++)
p[i]=0;
for (int i=0;i<l;i++)
{
if (s[i]>'1' && s[i]<='9')
p[s[i]-'0']++;
if (s[i]=='A')
p[1]++;
if (s[i]=='J')
p[11]++;
if (s[i]=='Q')
p[12]++;
if (s[i]=='K')
p[13]++;
if (s[i]=='1')
{
p[10]++;
}
}
tot=0;
for (int i=1;i<=13;i++)
if (p[i]!=0)
{
x[tot]=i;
y[tot]=p[i];
tot++;
}
if (tot==5)
{
if (x[0]==1 && x[1]==10)
a[j].sum=ll*8;
o=0;
for (int i=1;i<tot;i++)
if (x[i]!=x[i-1]+1)
o=1;
if (o==0)
a[j].sum=ll*7+x[0];
else
for (int i=0;i<tot;i++)
a[j].sum+=x[i];
}
if (tot==4)
{
for (int i=0;i<tot;i++)
if (y[i]==2)
o=x[i];
a[j].sum=ll*2+o*10000;
for (int i=0;i<tot;i++)
if (y[i]==1)
a[j].sum+=x[i];
}
if (tot==3)
{
for (int i=0;i<tot;i++)
if (y[i]==1)
a[j].sum+=x[i];
for (int i=0;i<tot;i++)
if (y[i]==3)
a[j].sum+=ll*4+x[i]*10000;
o=0;
for (int i=0;i<tot;i++)
if (y[i]==2)
{
if (o==0)
{
a[j].sum+=ll*3+x[i]*100;
o++;
}
else
a[j].sum+=x[i]*10000;
}
}
if (tot==2)
{
for (int i=0;i<tot;i++)
{
if (y[i]==1)
a[j].sum+=x[i];
if (y[i]==2)
a[j].sum+=x[i]*100;
if (y[i]==3)
a[j].sum+=ll*5+x[i]*10000;
if (y[i]==4)
a[j].sum+=ll*6+x[i]*10000;
}
}
if (tot==1)
a[j].sum=x[0]*5;
}
sort(a,a+n);
for (int i=n-1;i>=0;i--)
cout<<a[i].name<<endl;
for (int i=0;i<n;i++)
a[i].sum=0;
}
}
第三题
题意
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
思路
mx就是最大值+y,mn就是先将人从当前坐的最少的长凳上补,补到max,所有的长凳都补到max之后若还有剩余,则平均分摊,否则就是max。
代码
#include<iostream>
using namespace std;
int main()
{
int n,x,y,z,sum,min,max;
cin>>n>>y;
sum=0;
max=0;
min=100010;
for (int i=0;i<n;i++)
{
cin>>x;
if (x>max)
max=x;
if (x<min)
min=x;
sum=sum+x;
}
min=max;
while (min*n<sum+y)
min++;
cout<<min<<" "<<max+y<<endl;
return 0;
}