A - 咕咕东的目录管理器

题面

咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!

初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。

目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序

现在咕咕东可以在命令行下执行以下表格中描述的命令:

命令 类型 实现 说明
MKDIR s 操作 在当前目录下创建一个子目录 s,s 是一个字符串 创建成功输出 “OK”;若当前目录下已有该子目录则输出 “ERR”
RM s 操作 在当前目录下删除子目录 s,s 是一个字符串 删除成功输出 “OK”;若当前目录下该子目录不存在则输出 “ERR”
CD s 操作 进入一个子目录 s,s 是一个字符串(执行后,当前目录可能会改变) 进入成功输出 “OK”;若当前目录下该子目录不存在则输出 “ERR”。特殊地,若 s 等于 “…” 则表示返回上级目录,同理,返回成功输出 “OK”,返回失败(当前目录已是根目录没有上级目录)则输出 “ERR”
SZ 询问 输出当前目录的大小 也即输出 1+当前目录的子目录数
LS 询问 输出多行表示当前目录的 “直接子目录” 名 若没有子目录,则输出 “EMPTY”;若子目录数属于 [1,10] 则全部输出;若子目录数大于 10,则输出前 5 个,再输出一行 “…”,输出后 5 个。
TREE 询问 输出多行表示以当前目录为根的子树的前序遍历结果 若没有后代目录,则输出 “EMPTY”;若后代目录数+1(当前目录)属于 [1,10] 则全部输出;若后代目录数+1(当前目录)大于 10,则输出前 5 个,再输出一行 “…”,输出后 5 个。若目录结构如上图,当前目录为 “root” 执行结果如下,
UNDO 特殊 撤销操作 撤销最近一个 “成功执行” 的操作(即MKDIR或RM或CD)的影响,撤销成功输出 “OK” 失败或者没有操作用于撤销则输出 “ERR”
输入

输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);

每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);

每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);

面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。

输出

每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。

时空限制
时间限制 空间限制
6000 ms 1048576 kB
样例输入

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

样例输出

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

hint

英文原版题面:

分析

重点难点题目。此题非常复杂,不光是步骤繁琐,还有两处地方要进行算法的优化来避免超时,一般想不到这些方法。对于此题目:
解题的大体思路课件中有讲,主要是SZ操作和TREE操作要进行优化。

对于SZ操作。

在SZ操作中,复杂度中出现的1e5次查询由来为,当考虑最坏情况,因为MKDIR、RM操作总数不超过5000,所以可以有MKDIR、RM操作总数尽可能的少,操作全部为1e5次查询操作。

然后考虑多存储一个信息sz,表示以这个点为跟根的子树的规模。可以使sz复杂度降为O(1)。即:

此时再重新估算一下复杂度,因为MKDIR、RM操作总数不超过5000,当有5000次MKDIR操作时,也可以出现5000次UNDO,而每次MKDIR都要从最下面开始向上传导更新sz,所以计算量为1+2+……+5000,同样每次UNDO也是从下面往上传导(更新sz的数量都要-1),计算量也是1+2+……+5000,加上20组数据后总的计算量大约为5000 * 5000/2 * 2 * 20 = 5e8<6e8(6s差不多可以处理6e8以内的数据计算量,1s差不多可以处理1e8)。

而另一个重要的TREE操作是最难的。其中1e5的由来同上。得到的最大计算量为5000 * 1e5 * 20 = 1e10显然不行。便有:
其中较为重要的代码片段为:(确定每个点的pre和back,同时将该点标记为已经找过的点,即代表在未进行新的创建或者删除操作时,该点的pre和back情况不会改变)

void pushDown(int id) {node[id].pre.clear();//更新后pre和back清空,重新计算node[id].back.clear();pretrack(id);//正向找到前面的数if (node[id].sz > 10)backtrack(id);//反向找最后几个数else node[id].back = node[id].pre;//因为<=10个所以back与pre可以相同node[id].flag = 1;//标记为已经找过该点
}

此时因为每个点都最多更新一次,即TREE操作1e5的指令的复杂度可以降到5000(树的最大规模为5000)。

总结

  • 利用时限计算复杂度设计数据结构:

    • 设计树形数据结构时可以用map以O(logn)的复杂度来找子目录而不用O(n)。同时用map可以自动排序使满足 每个目录的儿子必须保持字典序 的条件。
    • 分析时限,发现TREE操作暴力实现是不可取的,于是用了记忆化(缓存,懒更新)的小技巧。
  • 从何入手:
    • 如果不知道从何入手,就从int main()开始先写几行。
    • 对于一个操作不要一上来就写细节,可以假装已经封装好了,先关注整体设计,这点在这道题中尤为重要。如果先不考虑整体,到时候UNDO操作实现就会比较麻烦。

C++

#include<bits/stdc++.h>
using namespace std;
int cnt, q, now;
const int maxn = 1e5 + 10;
const string cmd_[] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };//各指令
vector<pair<string, pair<int, int>>> v;//用来存有效操作,便于UNDO的实现struct Directory {string name;//这个点的名字map<string, int> mp;//根据子目录的名字取到它的子目录int sz, fa;//分别是处理SZ操作时表示以这个点为根的子树的规模,和该节点的父亲节点vector<string> pre, back;//处理TREE操作时前序遍历的前几个和后几个bool flag;//处理TREE操作时标记是否被更新过(实现懒更新)void init(string s,int p) {flag = 0;fa = p;name = s;sz = 1;pre.clear();back.clear();mp.clear();}
}node[maxn];//链式前向星记录走到哪一个位置了struct Command {string str, tr;//操作的名字和后面跟着的字符串int type;//操作转换为int类型void init(string s) {str = s;for (int i = 0; i < 7; i++) {if (s == cmd_[i]) {type = i;if (i < 3)cin >> tr;break;}}}
}cmd;void init() {cnt = 0;now = 0;v.clear();node[0].init("root", -1);}void insertNode(string s,int pa) {node[++cnt].init(s, pa);//节点s的序号为cntnode[pa].mp[s] = cnt;//父亲节点中字符串为s的孩子结点对应的序号为cnt,放入mp
}void update(int id, int num) {while(id != -1) {node[id].flag = 0;//注意该过程中所有点要标记为0,表示更新了,TREE操作需要更新node[id].sz += num;id = node[id].fa;}
}void mkdir() {if (node[now].mp.count(cmd.tr)) {//当前目录下已有该子目录了cout << "ERR" << "\n";return;}insertNode(cmd.tr, now);//在当前目录下创建一个子目录update(now, 1);//更新v.push_back({ "MKDIR",{now,cnt} });//现在节点与子目录节点的连接放入有效操作vcout << "OK" << "\n";
}void rm() {if (!node[now].mp.count(cmd.tr)) {//当前目录下没有该子目录cout << "ERR" << "\n";return;}int sonId = node[now].mp[cmd.tr];//得到要删除的子目录对应的序号update(now, (-1)*node[sonId].sz);//因为该子目录还有sz大小的子节点数node[now].mp.erase(cmd.tr);v.push_back({ "RM", { now,sonId } });//现在节点与子目录节点的连接放入有效操作vcout << "OK" << "\n";
}
void cd() {if (cmd.tr == "..") {if (node[now].fa == -1) {cout << "ERR" << "\n";return;}v.push_back({ "CD",{now,node[now].fa} });now = node[now].fa;cout << "OK" << "\n";return;}if (!node[now].mp.count(cmd.tr)) {cout << "ERR" << "\n";return;}int sonId = node[now].mp[cmd.tr];//得到要进入的子目录对应的序号v.push_back({ "CD",{now,sonId} });//现在节点与子目录节点的连接放入有效操作vnow = sonId;//替换cout << "OK" << "\n";
}void sz() {cout << now[node].sz << "\n";
}void undo() {if (v.size()==0) {cout << "ERR" << "\n";return;}auto e = v[v.size() - 1];v.pop_back();cout << "OK" << "\n";if (e.first == "MKDIR") {int sonId = e.second.second;//得到之前创建子目录的序号update(now, (-1)*node[sonId].sz);node[now].mp.erase(node[sonId].name);//父节点中移除该子目录}else if(e.first == "RM"){int sonId = e.second.second;update(now, node[sonId].sz);node[now].mp[node[sonId].name] = sonId;}else {now = e.second.first;}
}void ls() {int sonNum = node[now].mp.size();if (sonNum == 0) {cout << "EMPTY" << "\n";return;}auto pos = node[now].mp.begin();if (sonNum >= 1 && sonNum <= 10) {while (pos != node[now].mp.end()) {cout << pos->first << "\n";pos++;}return;}for (int i = 1; i <= 5; i++) {cout << pos->first << "\n";pos++;}cout << "..." << "\n";pos = node[now].mp.end();//pos = node[now].mp.end()-5;不行for (int i = 0; i < 5; i++)pos--;for (int i = 0; i < 5; i++) {cout << pos->first << "\n";pos++;}
}
void pushDown(int id);void pretrack(int id) {node[id].pre.push_back(node[id].name);//pre中先存入自己if (node[id].sz == 1)return;if (node[id].sz <= 10) {for (auto i : node[id].mp) {if (!node[i.second].flag) pushDown(i.second);//如果有孩子结点则把孩子结点的pre全部添加在父节点之前的pre的后面node[id].pre.insert(node[id].pre.end(), node[i.second].pre.begin(), node[i.second].pre.end());}return;}int cnt_ = 1;for (auto i : node[id].mp) {if (!node[i.second].flag) pushDown(i.second);for (auto j : node[i.second].pre) {//孩子结点的pre进行遍历放入父节点的pre中node[id].pre.push_back(j);++cnt_;if (cnt_ >= 5)break;}if (cnt_ >= 5)break;}
}
void backtrack(int id) {int cnt__ = 0;auto it = node[id].mp.end();//父节点的最后一个孩子结点--it;for (;; it--) {//从父节点的最后一个孩子结点向前遍历if (!node[it->second].flag) pushDown(it->second);int sonId = it->second;for (int i = node[sonId].back.size() - 1; i >= 0; i--) {//从孩子结点的最后一个孩子结点开始放入父节点的back中node[id].back.push_back(node[sonId].back[i]);cnt__++;if (cnt__ >= 5) {reverse(node[id].back.begin(), node[id].back.end());//因为从最后开始push_back的,所以要转置break;}}if (cnt__ >= 5)break;if (it == node[id].mp.begin())break;}
}void pushDown(int id) {node[id].pre.clear();//更新后pre和back清空,重新计算node[id].back.clear();pretrack(id);//正向找到前面的数if (node[id].sz > 10)backtrack(id);//反向找最后几个数else node[id].back = node[id].pre;//因为<=10个所以back与pre可以相同node[id].flag = 1;//标记为已经找过该点
}void tree() {if (!node[now].flag) pushDown(now);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] << "\n";}else {for (int i = 0; i < 5; i++)cout << node[now].pre[i] << "\n";cout << "..." << "\n";for (int i = 5; i >= 1; i--)cout << node[now].back[node[now].back.size() - i] << "\n";}
}
void solve() {init(); cin >> q;while (q--) {string s;cin >> s;cmd.init(s);switch (cmd.type){case 0:mkdir();break;case 1:rm();break;case 2:cd();break;case 3:sz();break;case 4:ls();break;case 5:tree();break;case 6:undo();break;default:break;}}
}
int main() {int t; cin >> t;while (t--) {solve();}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 张牌不同,其值不同。下面依次列举了这手牌的形成规则:

  1. 大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。

  2. 对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。

  3. 两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。

  4. 三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。

  5. 三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。

  6. 炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。

  7. 顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。

  8. 龙顺: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

分析

此题与之前写过的一道模拟题十分类似,参考程序设计思维与实践 Week6 限时大模拟。

此次忽略了花色,并且每张牌的数量都是不限的,此次并不是计算每种类型的数量,而是根据每个人的手中的牌依次根据三个指标比较大小进行排序。

  • 第一个指标是牌的类型,在card这个表示牌的结构体中用case0存储(注意如果用case作为变量名的话,case可能是关键字),这里为了方便后面的处理,先将输入的字符串中的A, J, Q, K Z先转为数字存在对应的value数组中,这里还是根据之前题目的思路来判断牌的类型,也是先要根据牌的大小进行排序,然后依次根据牌的数量大小判断属于哪一种类型。

  • 然后最不同的一点是,要得到第二个指标:每个人手中牌的大小(类似于几个人真正打扑克牌中的要不要得起),这里得到的值用sum存储。这里的sum不是牌大小的简单加和,因为在一些类型下,牌的大小的计算具有优先级,这里用的是乘以了一定的不同的倍数来表示优先级,目的是只要能比较出相同类型的牌的大小即可(或者可以定义几个不同的变量来赋值定义优先级顺序,这里我直接用了一个变量计算表示出来)。如果有两种优先级,一般是较大优先级的数字 * 100,不能 * 10,因为比如有两组数AAAKK和222AA,根据三个优先级较大得出应该是后者牌的大小较大,但是如果是10倍计算得出分别是:1 * 10+13 = 23 和 2 * 10+1 = 21,等等例子都可以佐证。特别要注意在几个特殊的类型下的倍数的选择!!!本来我以为三种优先级的话,最大优先级 *1000就够了,但是得到一些反例比如:两组数QQJJ10中sum大小为12000+1100+10 = 13110和AAKK2中sum大小为13000+100+2 = 13102 < 13110,不符合实际情况的后者大小大于前者。所以还是要 * 10000。

  • 第三个指标便是人名字典序。

  • 其他的一些对于类型的判断条件与之前的题目类似。

C++

#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
struct card {string name, num;//字符串类型的名字和紧跟着的他手里的牌情况int case0, sum = 0, value[6];//分别表示牌的类型,牌的总和大小,5张牌分别代表的数值(用value数值存储)
};
bool comp(const card &a, const card &b)
{//自定义排序,先根据类型比较,类型相同根据牌的总和大小比较,如果还是相同则比较字符串大小。if (a.case0 == b.case0) return a.sum == b.sum ? a.name<b.name : a.sum>b.sum;else return a.case0 > b.case0;
}
void change(card &ca) {//各个字符串的换成数字大小进行比较string s = ca.num;int siz = s.length();int cnt = 1;for (int i = 0; i < siz; i++) {if (s[i] == 'A') ca.value[cnt++] = 1;else if (s[i] == 'J')ca.value[cnt++] = 11;else if (s[i] == 'Q')ca.value[cnt++] = 12;else if (s[i] == 'K')ca.value[cnt++] = 13;else if (s[i] == '1') {ca.value[cnt++] = 10;i++;}else ca.value[cnt++] = s[i] - '0';}
}
bool check8(card car) {if (car.value[1] == 1 && car.value[2] == 10 && car.value[3] == 11 && car.value[4] == 12 && car.value[5] == 13)return true;return false;
}
bool check7(card &car) {for (int i = 2; i <= 5; i++)if (car.value[i] - car.value[i - 1] != 1)return false;car.sum = car.value[5];return true;
}
bool check6(card &car) {if (car.value[1] == car.value[2] && car.value[2] == car.value[3] && car.value[3] == car.value[4]) { car.sum = 100*car.value[1]+car.value[5]; return true; }else if (car.value[2] == car.value[3] && car.value[3] == car.value[4] && car.value[4] == car.value[5]) { car.sum = 100*car.value[2]+car.value[1]; return true; }return false;
}
bool check5(card &car) {if (car.value[1] == car.value[2] && car.value[2] == car.value[3] && car.value[4] == car.value[5]) { car.sum = 100 * car.value[1] + car.value[5]; return true; }else if (car.value[1] == car.value[2] && car.value[3] == car.value[4] && car.value[4] == car.value[5]) { car.sum = 100 * car.value[5] + car.value[1]; return true; }return false;
}
bool check4(card &car) {if (car.value[1] == car.value[2] && car.value[2] == car.value[3]) { car.sum = 100 * car.value[1] + car.value[4] + car.value[5]; return true; }else if (car.value[3] == car.value[4] && car.value[2] == car.value[3]) { car.sum = 100 * car.value[2] + car.value[1] + car.value[5]; return true; }else if (car.value[3] == car.value[4] && car.value[4] == car.value[5]) { car.sum = 100 * car.value[3] + car.value[1] + car.value[2]; return true; }return false;
}
bool check3(card &car) {//注意这种情况下倍数!的运用if (car.value[1] == car.value[2] && car.value[4] == car.value[5]) { car.sum = 10000 * car.value[4] + 100 * car.value[1] + car.value[3]; return true; }else if (car.value[1] == car.value[2] && car.value[3] == car.value[4]) { car.sum = 10000 * car.value[4] + 100 * car.value[1] + car.value[5]; return true; }else if (car.value[2] == car.value[3] && car.value[4] == car.value[5]) { car.sum = 10000 * car.value[4] + 100 * car.value[2] + car.value[1]; return true; }return false;
}
bool check2(card &car) {for (int i = 1; i <= 4; i++) {if (car.value[i] == car.value[i+1]) {car.sum = 100 * car.value[i];for (int j = 1; j <= 5; j++) if (j != i && j != i + 1)car.sum += car.value[j];return true;}}return false;
}
void check(card &ca) {//得到类型大小change(ca); sort(ca.value + 1, ca.value + 6);if (check8(ca))ca.case0 = 8;else if (check7(ca)) ca.case0 = 7;else if (check6(ca)) ca.case0 = 6;else if (check5(ca)) ca.case0 = 5;else if (check4(ca)) ca.case0 = 4;else if (check3(ca)) ca.case0 = 3;else if (check2(ca)) ca.case0 = 2;else {ca.sum = ca.value[1]+ca.value[2]+ca.value[3]+ca.value[4]+ca.value[5];ca.case0 = 1;}
}
int n;
vector<card> result;
int main() {while (scanf("%d", &n) != EOF) {result.clear();//记得清空while (n--) {card ca;//不能放外边cin >> ca.name >> ca.num;check(ca);result.push_back(ca);}sort(result.begin(), result.end(), comp);//在while外for (int i = 0; i < result.size(); i++) {cout << result[i].name << endl;}}return 0;
}

C - 签到题,独立思考哈

SDUQD 旁边的滨海公园有 x 条长凳。第 i 个长凳上坐着aia_iai​ 个人。这时候又有 y 个人将来到公园,他们将选择坐在某些公园中的长凳上,那么当这 y 个人坐下后,记k = 所有椅子上的人数的最大值,那么k可能的最大值mx和最小值mn分别是多少。

Input

第一行包含一个整数 x (1 <= x <= 100) 表示公园中长椅的数目
第二行包含一个整数 y (1 <= y <= 1000) 表示有 y 个人来到公园
接下来 x 个整数 aia_iai​ (1<=aia_iai​<=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

分析

此题相对比较简单。

  • k可能的最大值mx直接由初始时椅子上最大人数mx_0加上后来来的y个人即可;
  • 求k可能的最小值mn时,尽量将新来的人分配到使每条长椅上的人数尽量均匀,先求出平均分配时,每条长椅上应该有的人数,再将之前得到的初始时椅子上最大人数mx_0与之做比较,如果mx_0大于平均值,那么k最小值也只能是mx_0了;如果不小于,则先判断平均值是否是整数(temp*x == sum+y或者(sum+y)%x == 0),如果是,则可以平均分配,得到的k可能的最小值就是平均值temp,如果平均值还有余数,那么不能整数平均分配,则最终的结果会平均值+1。

C++

#include <iostream>
#include<algorithm>
using namespace std;int main(){int x,y,a[200],mx=0,mn=0,sum=0;cin>>x>>y;for(int i = 1;i<=x;i++){cin>>a[i];mx = max(a[i],mx);//得出初始时椅子上最多人数,+y直接可以得出k可能的最大值sum += a[i];//求出初始总人数}int temp = (sum+y)/x;//求出加入人后的每条椅子上人数的平均值if(mx>temp) mn = mx;else {if(temp*x==sum+y) mn = temp;else mn = temp+1;}mx+=y;cout<<mn<<" "<<mx<<endl;return 0;
}

程序设计思维与实践 Week9 作业三道相关推荐

  1. 程序设计思维与实践 Week9 作业 A 咕咕东的目录管理器

    题目描述: 咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 -- 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始 ...

  2. 程序设计思维与实践 Week9 作业 (3/4/数据班)

    A-咕咕东的目录管理器 题意: 咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 -- 这工程量太大了,所以他定了一个小目标,从实 ...

  3. 程序设计思维与实践Week9 作业 (1/2/智能班)

    A - 咕咕东的目录管理器 题面 咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 -- 这工程量太大了,所以他定了一个小目标,从 ...

  4. 程序设计思维与实践 Week15 作业A - ZJM 与霍格沃兹

    题意: ZJM 为了准备霍格沃兹的期末考试,决心背魔咒词典,一举拿下咒语翻译题 题库格式:[魔咒] 对应功能 背完题库后,ZJM 开始刷题,现共有 N 道题,每道题给出一个字符串,可能是 [魔咒],也 ...

  5. 程序设计思维与实践 Week15 作业 A-ZJM与霍格沃兹

    题目链接:A-ZJM与霍格沃兹 题目描述: ZJM 为了准备霍格沃兹的期末考试,决心背魔咒词典,一举拿下咒语翻译题 题库格式:[魔咒] 对应功能 背完题库后,ZJM 开始刷题,现共有 N 道题,每道题 ...

  6. 程序设计思维与实践 Week12 作业 必做题 A-zjm找数

    题目链接:A-zjm找数 题目描述: 给出n个数,zjm想找出出现至少(n+1)/2次的数, 现在需要你帮忙找出这个数是多少? Input: 本题包含多组数据: 每组数据包含两行. 第一行一个数字N( ...

  7. 【20200401程序设计思维与实践 Week7作业】

    目录 A - TT 的魔法猫 题意 思路 总结 代码 B - TT 的旅行日记 题意 思路 总结 代码 C - TT 的美梦 题意 思路 总结 代码 A - TT 的魔法猫 题意 众所周知,TT 有一 ...

  8. 程序设计思维与实践 Week2 作业 B - Pour Wate

    题目描述: 倒水问题 "fill A" 表示倒满A杯,"empty A"表示倒空A杯,"pour A B" 表示把A的水倒到B杯并且把B杯倒 ...

  9. 程序设计思维与实践 Week8 作业 C - 班长竞选

    题目描述 大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收 ...

最新文章

  1. 一步一步写算法(检查表)
  2. 快速使用wordpress
  3. 图像处理之ROI区域裁剪
  4. JavaScript级联国家地区
  5. python装饰器打印函数执行时间_python装饰器计算函数执行时间
  6. 【java】javac命令在win10不可用,提示javac不是内部或外部命令,也不是可运行的程序【解决方法】
  7. AIR学习教程(一)
  8. 万能的SuperSlide
  9. 线性时不变系统——信号系统学习笔记
  10. linux搭建泰拉瑞亚(Terraria)服务器
  11. mysql时间分钟比较_MySql中时间比较方法 周 小时 分钟
  12. 软件测试面试总被拒怎么办?表姐把压箱底的面试秘籍交给了我,现在已经在上班了。
  13. 数据仓库ods层是啥意思_一文读懂大数据仓库建设
  14. video dispose
  15. 知识蒸馏论文读书笔记
  16. 实时自动驾驶车辆定位技术都有哪些?(视觉/Lidar/多传感器数据融合)
  17. 数学建模第一讲:层次分析法
  18. 网站快照被劫持怎么办?
  19. python是高级程序语言_高级语言程序设计(Python)_中国大学MOOC(慕课)
  20. 正则表达式(国际固话和手机号码)

热门文章

  1. 计算机发展的六大趋势,曙光总裁历军:高性能计算机发展六大趋势
  2. 《图解UE4渲染体系》Part 1 多线程渲染
  3. 专栏《乔新亮的CTO成长复盘》读书笔记(一)
  4. BI业务分析思维:现金流量风控分析(三)风险控制
  5. 全国计算机应用考试试卷,全国自考计算机应用基础历年试题含答案
  6. 车联网全景扫描——DSRC与C-V2X
  7. fx系列微型可编程控制器 通信_三菱Q系列和FX系列的PLC有什么区别?
  8. 怪怪设计论: 抽象无处不在
  9. Java设计模式(六)— 单例模式1
  10. QMT量化交易软件使用攻略(四)-策略回测