A咕咕东的目录管理器
题目
input&&output
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
#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
题解
1本题代码采用面向对象的方式编写
2.由于基本嫖自课堂助教,,因此不做分析
3.本题用到的思想比较惊艳的地方我认为是,模拟缓存的使用,极大的加快了目录索引效率
C++代码
#include <stdio.h>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <iterator>
using namespace std;
int T;
char tmps[20];
struct Directory{
string name; //当前目录名称
map<string, Directory*> children;//找子
vector<string>* tenDescendants;//类似缓存
bool updated;//是否需要更新
Directory* parent; //以备cd..返回上级目录
int subtreeSize;//子树大小
Directory(string newname, Directory* newparent){//构造
this->name=newname;
this->parent=newparent;
this->subtreeSize=1;
this->updated=false;
children.clear();
tenDescendants=new vector<string>;
}
public:
Directory *getChild(const string& newname){
auto it=children.find(newname);
if(it==children.end())
return nullptr;
return it->second;
}
Directory* mkdir(const string& newname){
auto it=children.find(newname);
if(it!=children.end())
return nullptr;
Directory* ch = new Directory(newname,this);
children[newname]=ch;
maintain(+1);
return ch;
}
Directory* rm(const string& newname){
auto it=children.find(newname);
if(it==children.end())
return nullptr;
maintain(-1*(it->second->subtreeSize));
children.erase(it);
return it->second;
}
Directory* cd(const string& newname){
if(".."==newname)
return this->parent;
return getChild(newname);
}
bool addChild(Directory* ch){
auto it=children.find(ch->name);
if(it!=children.end())
return false;
children[ch->name] = ch;
maintain(ch->subtreeSize);
return true;
}
void maintain(int delta){
updated=true;
subtreeSize+=delta;
if(parent!=nullptr)
parent->maintain(delta);
}
void sz(){
printf("%d\n",this->subtreeSize);
}
void ls(){
int sz=children.size();
if(sz==0) printf("EMPTY\n");
else if(sz<=10){
for(auto& entry:children)
printf("%s\n",entry.first.c_str());
}
else{
auto it=children.begin();
for(int i=0;i<5;i++,it++)
printf("%s\n",it->first.c_str());
printf("...\n");
it=children.end();
for(int i=0;i<5;i++) it--;
for(int i=0;i<5;i++,it++)
printf("%s\n",it->first.c_str());
}
}
void tree(){
if(subtreeSize==1) printf("EMPTY\n");
else if(subtreeSize<=10){
if(this->updated){
tenDescendants->clear();
treeAll(tenDescendants);
this->updated=false;
}
for(int i=0;i<subtreeSize;i++)
printf("%s\n",tenDescendants->at(i).c_str());
}else{
if(this->updated){
tenDescendants->clear();
treeFirstSome(5,tenDescendants);
treeLastSome(5,tenDescendants);
this->updated=false;
}
for(int i=0;i<5;i++)
printf("%s\n",tenDescendants->at(i).c_str());
printf("...\n");
for(int i=9;i>=5;i--)
printf("%s\n",tenDescendants->at(i).c_str());
}
}
private:
void treeAll(vector<string>* bar){
bar->push_back(name);
for(auto &entry : children)
entry.second->treeAll(bar);
}
void treeFirstSome(int num, vector<string>* bar){
bar->push_back(name);
if(--num==0) return;
int n=children.size();
auto it=children.begin();
while(n--){
int sts=it->second->subtreeSize;
if(sts>=num){
it->second->treeFirstSome(num,bar);
return;
}else{
it->second->treeFirstSome(sts,bar);
num-=sts;
}
it++;
}
}
void treeLastSome(int num,vector<string>* bar){
int n=children.size();
auto it=children.end();
while(n--)
{
it--;
int sts=it->second->subtreeSize;
if(sts>=num)
{
it->second->treeLastSome(num,bar);
return;
}else{
it->second->treeLastSome(sts,bar);
num-=sts;
}
}
bar->push_back(name);
}
};
struct Command{
const string CMDNAMES[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
int type;
string arg;
Directory* tmpDir;//刚刚操作的节点
Command(const string& s){
tmpDir=nullptr;
for (int i=0;i<7;i++)
if(CMDNAMES[i]==s){
type=i;
if(i<3) scanf("%s",tmps),arg=tmps;
return;
}
}
};
void solve(){
int n;
scanf("%d",&n);
Directory* now=new Directory("root",nullptr);
vector<Command*> cmdList;
cmdList.clear();
while(n--){
scanf("%s",tmps);
Command* cmd=new Command(tmps);
switch(cmd->type){
case 0:case 1:{//MKDIR、RM
cmd->tmpDir=cmd->type==0? now->mkdir(cmd->arg) : now->rm(cmd->arg);
if(cmd->tmpDir==nullptr) printf("ERR\n");
else {
printf("OK\n");
cmdList.push_back(cmd);
}
break;
}
case 2:{//CD
Directory* ch=now->cd(cmd->arg);
if(ch==nullptr) printf("ERR\n");
else{
printf("OK\n");
cmd->tmpDir=now;
now=ch;
cmdList.push_back(cmd);
}
break;
}
case 3://SZ
now->sz();
break;
case 4://LS
now->ls();
break;
case 5://TREE
now->tree();
break;
case 6://UNDO
{
bool success=false;
while(!success && !cmdList.empty()){
cmd=cmdList.back();
cmdList.pop_back();
switch(cmd->type){
case 0:
success=now->rm(cmd->arg)!= nullptr;
break;
case 1:
success=now->addChild(cmd->tmpDir);
break;
case 2:
now=cmd->tmpDir;
success=true;
break;
}
}
printf(success ? "OK\n" : "ERR\n");
}
}
}
}
int main(){
scanf("%d",&T);
for(int i=0;i<T;i++){
solve();
if(i!=(T-1)) printf("\n");
}
return 0;
}
B东东学打牌
题目
input&&output
Sample
#input:
3
DongDong AAA109
ZJM 678910
Hrz 678910
#output:
Hrz
ZJM
DongDong
题解
1.本题实际上曾经做过类似的,我们只需要对牌型做一个排名就可以乐
2.八类牌,相同牌型之间按照牌型内部的顺序排列,牌相同按照姓名牌,我们只需要
写出一个排序函数就好了
首先我们只考虑牌型,八类牌分别为 1~8
此处我们利用(五张牌排序后的)一个差值数组,并且只关注其中差值为0 1的位置及个数
并且由于有龙顺,因此将牌扩展一位 默认15 含A则为14
大牌就是1,也就是不属于后七种
对子:0的个数为1
三张:0的个数为2,与两对区别在非零的位置(或者我们可以注意到他的0是连续的位置)
两对:0的个数为2
三带二:0的个数3
炸弹:0的个数3,区别于三代二是 相同牌占位的跨度 XXXXA | AXXXX
顺子:1的个数为4
龙顺:1的个数为4,但第一个位置非零
注意:类似这种的数据 A123K (也是四个1 顺子需要特判一下
然后我们看相同牌型:
我们发现 最多牌型相同时最多需要判断 三次(两对时 )
因此我们通过一个长度为4的数组记录整个牌的特征量
(牌型,第一特征,第二特征,第三特征)
如 AA223 -> [3,2,1,3]
PS:注意一对时第二特征为剩余牌的和
C++代码
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
struct p{
string name;
int poke[6];//出现A记录一个14
int sum(){
return poke[0]+poke[1]+poke[2]+poke[3]+poke[4];
}
};
vector<p> v(0);
int n;
char a[] = {'A','2','3','4','5','6','7','8','9','Z','J','Q','K'};
int c2n(char now){
for(int i=0;i<sizeof a;i++)
if(a[i]==now) return i+1;
}
int mark[16];
void typ(p x,int* re){
for(int i=0;i<5;i++) re[i] = 0;//返回牌型 以及具体信息 0表示牌型 1对应牌型的第一标识 2 第二标识... ————关于对子和三张 第二标识是剩余和!!! 2
re[0] = 1;//默认是大牌
int diff[5],stat[2];//diff 差(特征)数组 stat 状态数组 只记录 差数组的 0 1
for(int i=0;i<5;i++) diff[i] = 0;
stat[0] = 0,stat[1] = 0;
for(int i=0;i<5;i++){
diff[i] = x.poke[i+1]-x.poke[i];
if(diff[i] == 0||diff[i] == 1) stat[diff[i]]++;
}
if(stat[0] == 1){//一对
re[0] = 2;
for(int i=4;i>=0;i--)
if(re[1] == 0 && diff[i-1] == 0) re[1] = x.poke[i--];//升序排列后面的更大
else re[2] += x.poke[i];
}
if(stat[0] == 2){//三张 或 两对
if((diff[3]!=0&&(diff[0]!=0||diff[2]!=0)) || (diff[0] != 0 && diff[1] != 0)){//三张
re[0] = 4,re[1] = x.poke[2],re[2] = x.sum()-3*re[1];
}else{//两对
re[0] = 3,re[1] = x.poke[3],re[2] = x.poke[1];
if(diff[3] != 0) re[3] = x.poke[4];
else if(diff[0] != 0) re[3] = x.poke[0];
else re[3] = x.poke[2];
}
}
if(stat[0] >= 3){//三代二 或 炸弹
if(x.poke[0] == x.poke[3] || x.poke[1] == x.poke[4]){//炸弹
re[0] = 6,re[1] = x.poke[2],re[2] = x.sum() - 4*re[1];
}else{//0 1 2 3 4 五个位置 2一定是三张 然后根据1 2是否一样判断
re[0] = 5,re[1] = x.poke[2],re[2] = (x.sum() - 3*re[1])/2;
}
}
if(stat[1] == 4){
if(diff[0] != 1) re[0] = 8;
else{//注意类似这种的数据 A123K (也是四个1
if(x.poke[5] ==15 || (diff[0] == 1&&diff[1] == 1&&diff[2] == 1&&diff[3] == 1))
re[0] = 7,re[1] = x.poke[4];
}
}
}
bool s(p p1,p p2){//< 是小的在前 >是大的在前
int rep1[5],rep2[5];
typ(p1,rep1);
typ(p2,rep2);
for(int i=0;i<5;i++){
if(rep1[i] != rep2[i])
return rep1[i]>rep2[i];
}
if(rep1[0] == 1 && p1.sum() != p2.sum()) return p1.sum()>p2.sum();
return p1.name<p2.name;
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out2.txt","w",stdout);
while(cin>>n){
v = vector<p>(0);
v.clear();
string now,name;
while(n--){
for(int i=0;i<15;i++) mark[i] = 0;//1-14计数
cin>>name>>now;
int nowpoke[6];
for(int i=0;i<6;i++) nowpoke[i] = 0;
nowpoke[5] = 15;
for(int i=0;i<now.length();i++){
if(now[i]=='1') mark[10]++,i++;
else mark[c2n(now[i])]++;
if(now[i] == 'A' && mark[14] == 0){
mark[14]++;
nowpoke[5]=14;
}
}
int pos = 0;
for(int i=1;i<14;i++)
for(int j=0;j<mark[i];j++)
nowpoke[pos++] = i;
sort(nowpoke,nowpoke+6);
p ins;
ins.name = name;
for(int i=0;i<6;i++)
ins.poke[i] = nowpoke[i];
v.push_back(ins);
}
sort(v.begin(),v.end(),s);
for(int i=0;i<v.size();i++)
cout<<v[i].name<<endl;
}
return 0;
}
C签到题
题目
input&&output
Sample
#input:
3
7
1
6
1
#output:
6 13
题解
1.本题思路很多我才用的偏数学
2.首先我们看最大的最大(mx):
这个比较简单,我们只需要把新来的全安排到原有的最多的椅子上就可
然后肯最小的最大(mn):
我们会偏向于让最大值更小,因此先将人分配到小于当前最大的椅子上,然后每
个椅子分配一个直到分配结束
因此我们先将所有椅子的人数补到目前的最大个数,若无剩余或补不全则mn为当
前的最大个数,若补全我们只需要每个椅子分配一个人也就是除运算,如果刚刚
分配合理(mod运算为0)则为最大个数加除运算结果,否则再加一
C++代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> v(0);
int x,y,c,mx,mn;
int main(){
cin>>x>>y;
for(int i=0;i<x;i++){
cin>>c;
v.push_back(c);
}
sort(v.begin(),v.end());
mx = v[x-1] + y;
long long sum=y;
for(int i=0;i<v.size();i++)
sum+=v[i] - v[x-1];
//sum-=x-1;
if(sum<=0) mn = v[x-1];
else{
int add;
if(sum%x == 0) add=0;
else add = 1;
mn = v[x-1] + sum/x + add;
}
cout<<mn<<" "<<mx;
return 0;
}