注释:该解析不放置输入输出格式和输入输出样例,详情请参考PAT官网题目库。且我在解题之后还会参考柳神的代码做比较,学习好的部分,提升自己的代码。这里附上柳神的pat的github,有兴趣的小伙伴可去自行下载。github.com/liuchuo/PAT
1051 复数乘法 (15 分)
复数可以写成 (A+Bi) 的常规形式,其中 A 是实部,B 是虚部,i 是虚数单位,满足 =−1;也可以写成极坐标下的指数形式 ,其中 R 是复数模,P 是辐角,i 是虚数单位,其等价于三角形式 R(cos(P)+isin(P))。
现给定两个复数的 R 和 P,要求输出两数乘积的常规形式。
输入格式:
输入在一行中依次给出两个复数的 ,数字间以空格分隔。
输出格式:
在一行中按照 A+Bi
的格式输出两数乘积的常规形式,实部和虚部均保留 2 位小数。注意:如果 B
是负数,则应该写成 A-|B|i
的形式。
输入样例:
2.3 3.5 5.2 0.4
结尾无空行
输出样例:
-8.68-8.23i
结尾无空行
解析:
这道题只要输入正确公式就可以了。
代码:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double r1, p1, r2, p2, A, B;
cin >> r1 >> p1 >> r2 >> p2;
A = r1 * r2 * cos(p1) * cos(p2) - r1 * r2 * sin(p1) * sin(p2);
B = r1 * r2 * cos(p1) * sin(p2) + r1 * r2 * sin(p1) * cos(p2);
if (A + 0.005 >= 0 && A < 0)
printf("0.00");
else
printf("%.2f", A);
if(B >= 0)
printf("+%.2fi", B);
else if (B + 0.005 >= 0 && B < 0)
printf("+0.00i");
else
printf("%.2fi", B);
return 0;
}
1052 卖个萌 (20 分)
萌萌哒表情符号通常由“手”、“眼”、“口”三个主要部分组成。简单起见,我们假设一个表情符号是按下列格式输出的:
[左手]([左眼][口][右眼])[右手]
现给出可选用的符号集合,请你按用户的要求输出表情。
输入格式:
输入首先在前三行顺序对应给出手、眼、口的可选符号集。每个符号括在一对方括号 []
内。题目保证每个集合都至少有一个符号,并不超过 10 个符号;每个符号包含 1 到 4 个非空字符。
之后一行给出一个正整数 K,为用户请求的个数。随后 K 行,每行给出一个用户的符号选择,顺序为左手、左眼、口、右眼、右手——这里只给出符号在相应集合中的序号(从 1 开始),数字间以空格分隔。
输出格式:
对每个用户请求,在一行中输出生成的表情。若用户选择的序号不存在,则输出 Are you kidding me? @/@
。
输入样例:
[╮][╭][o][~][/~] [<][>]
[╯][╰][^][-][=][>][<][@][⊙]
[Д][▽][_][ε][^] ...
4
1 1 2 2 2
6 8 1 5 5
3 3 4 3 3
2 10 3 9 3
结尾无空行
输出样例:
╮(╯▽╰)╭
<(@Д=)/~
o(^ε^)o
Are you kidding me? @/@
结尾无空行
解析:
这道题的本质是分类输入,选择输出。选对容器很重要。
代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<vector<string> > v;
for(int i = 0; i < 3; i++) {
string s;
getline(cin, s);
vector<string> row;
int j = 0, k = 0;
while(j < s.length()) {
if(s[j] == '[') {
while(k++ < s.length()) {
if(s[k] == ']') {
row.push_back(s.substr(j+1, k-j-1));
break;
}
}
}
j++;
}
v.push_back(row);
}
int n;
cin >> n;
for(int i = 0; i < n; i++) {
int a, b, c, d, e;
cin >> a >> b >> c >> d >> e;
if(a > v[0].size() || b > v[1].size() || c > v[2].size() || d > v[1].size() || e > v[0].size() || a < 1 || b < 1 || c < 1 || d < 1 || e < 1) {
cout << "Are you kidding me? @\\/@" << endl;
continue;
}
cout << v[0][a-1] << "(" << v[1][b-1] << v[2][c-1] << v[1][d-1] << ")" << v[0][e-1] << endl;
}
return 0;
}
1053 住房空置率 (20 分)
在不打扰居民的前提下,统计住房空置率的一种方法是根据每户用电量的连续变化规律进行判断。判断方法如下:
- 在观察期内,若存在超过一半的日子用电量低于某给定的阈值 e,则该住房为“可能空置”;
- 若观察期超过某给定阈值 D 天,且满足上一个条件,则该住房为“空置”。
现给定某居民区的住户用电量数据,请你统计“可能空置”的比率和“空置”比率,即以上两种状态的住房占居民区住房总套数的百分比。
输入格式:
输入第一行给出正整数 N(≤1000),为居民区住房总套数;正实数 e,即低电量阈值;正整数 D,即观察期阈值。随后 N 行,每行按以下格式给出一套住房的用电量数据:
其中 K 为观察的天数, 为第 i 天的用电量。
输出格式:
在一行中输出“可能空置”的比率和“空置”比率的百分比值,其间以一个空格分隔,保留小数点后 1 位。
输入样例:
5 0.5 10
6 0.3 0.4 0.5 0.2 0.8 0.6
10 0.0 0.1 0.2 0.3 0.0 0.8 0.6 0.7 0.0 0.5
5 0.4 0.3 0.5 0.1 0.7
11 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
11 2 2 2 1 1 0.1 1 0.1 0.1 0.1 0.1
结尾无空行
输出样例:
40.0% 20.0%
结尾无空行
(样例解释:第2、3户为“可能空置”,第4户为“空置”,其他户不是空置。)
解析:
这道题的变量稍微有点多,要注意多重循环的使用。还有每一项数据的判断。
代码:
#include <iostream>
using namespace std;
int main() {
int n, d, k, day = 0;
double e, source, mightempty = 0,empty = 0;
cin >> n >> e >> d;
int t = n;
while (t--) {
cin >> k;
int kk = k;
day = 0;
while (kk--) {
cin >> source;
if (source < e)day++;
}
if (day > (k / 2)) {
k > d ? empty++ : mightempty++;
}
}
mightempty = mightempty / n * 100;
empty = empty / n * 100;
printf("%.1lf%c %.1lf%c" , mightempty,'%', empty, '%');
}
1054 求平均值 (20 分)
本题的基本要求非常简单:给定 N 个实数,计算它们的平均值。但复杂的是有些输入数据可能是非法的。一个“合法”的输入是 [−1000,1000] 区间内的实数,并且最多精确到小数点后 2 位。当你计算平均值的时候,不能把那些非法的数据算在内。
输入格式:
输入第一行给出正整数 N(≤100)。随后一行给出 N 个实数,数字间以一个空格分隔。
输出格式:
对每个非法输入,在一行中输出 ERROR: X is not a legal number
,其中 X
是输入。最后在一行中输出结果:The average of K numbers is Y
,其中 K
是合法输入的个数,Y
是它们的平均值,精确到小数点后 2 位。如果平均值无法计算,则用 Undefined
替换 Y
。如果 K
为 1,则输出 The average of 1 number is Y
。
输入样例 1:
7
5 -3.2 aaa 9999 2.3.4 7.123 2.35
结尾无空行
输出样例 1:
ERROR: aaa is not a legal number
ERROR: 9999 is not a legal number
ERROR: 2.3.4 is not a legal number
ERROR: 7.123 is not a legal number
The average of 3 numbers is 1.38
结尾无空行
输入样例 2:
2
aaa -9999
结尾无空行
输出样例 2:
ERROR: aaa is not a legal number
ERROR: -9999 is not a legal number
The average of 0 numbers is Undefined
结尾无空行
解析:
这道题就是遍历字符串,分类判断,统计求平均值。
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int main() {
int n, cnt = 0;
char a[50], b[50];
double temp = 0.0, sum = 0.0;
cin >> n;
for(int i = 0; i < n; i++) {
scanf("%s", a);
sscanf(a, "%lf", &temp);
sprintf(b, "%.2f",temp);
int flag = 0;
for(int j = 0; j < strlen(a); j++)
if(a[j] != b[j]) flag = 1;
if(flag || temp < -1000 || temp > 1000) {
printf("ERROR: %s is not a legal number\n", a);
continue;
} else {
sum += temp;
cnt++;
}
}
if(cnt == 1)
printf("The average of 1 number is %.2f", sum);
else if(cnt > 1)
printf("The average of %d numbers is %.2f", cnt, sum / cnt);
else
printf("The average of 0 numbers is Undefined");
return 0;
}
1055 集体照 (25 分)
拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下:
- 每排人数为 N/K(向下取整),多出来的人全部站在最后一排;
- 后排所有人的个子都不比前排任何人矮;
- 每排中最高者站中间(中间位置为 m/2+1,其中 m 为该排人数,除法向下取整);
- 每排其他人以中间人为轴,按身高非增序,先右后左交替入队站在中间人的两侧(例如5人身高为190、188、186、175、170,则队形为175、188、190、186、170。这里假设你面对拍照者,所以你的左边是中间人的右边);
- 若多人身高相同,则按名字的字典序升序排列。这里保证无重名。
现给定一组拍照人,请编写程序输出他们的队形。
输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出两个正整数 N(≤104,总人数)和 K(≤10,总排数)。随后 N 行,每行给出一个人的名字(不包含空格、长度不超过 8 个英文字母)和身高([30, 300] 区间内的整数)。
输出格式:
输出拍照的队形。即K排人名,其间以空格分隔,行末不得有多余空格。注意:假设你面对拍照者,后排的人输出在上方,前排输出在下方。
输入样例:
10 3
Tom 188
Mike 170
Eva 168
Tim 160
Joe 190
Ann 168
Bob 175
Nick 186
Amy 160
John 159
结尾无空行
输出样例:
Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John
结尾无空行
解析:
首先用结构体绑定姓名和身高,用vector容器进行排序。计算行数。左右交替输出采用指针+2的方式。
代码:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
struct Student {
string name;
int height;
};
int cmp(struct Student a, struct Student b) {return a.height != b.height ? a.height > b.height : a.name < b.name;}
int main() {
int n, k, m;
scanf("%d%d", &n, &k);
vector<Student> stu(n);
for(int i=0;i<n;i++)cin >> stu[i].name >> stu[i].height;
sort(stu.begin(), stu.end(), cmp);
int t = 0, row = k;
while (row) {
if (row == k)
m = n - n / k * (k - 1);
else
m = n / k;
vector<string> ans(m);
ans[m / 2] = stu[t].name;
int j = m / 2 - 1;
for (int i = t + 1; i < t + m; i = i + 2)
ans[j--] = stu[i].name;
j = m / 2 + 1;
for (int i = t + 2; i < t + m; i = i + 2)
ans[j++] = stu[i].name;
cout << ans[0];
for (int i = 1; i < m; i++)
cout << " " << ans[i];
cout << endl;
t = t + m;
row--;
}
}
1056 组合数的和 (15 分)
给定 N 个非 0 的个位数字,用其中任意 2 个数字都可以组合成 1 个 2 位的数字。要求所有可能组合出来的 2 位数字的和。例如给定 2、5、8,则可以组合出:25、28、52、58、82、85,它们的和为330。
输入格式:
输入在一行中先给出 N(1 < N < 10),随后给出 N 个不同的非 0 个位数字。数字间以空格分隔。
输出格式:
输出所有可能组合出来的2位数字的和。
输入样例:
3 2 8 5
结尾无空行
输出样例:
330
结尾无空行
解析:
这个就是简单的数学题,找到规律就好了。
代码:
#include <iostream>
using namespace std;
int main() {
int n,num,result = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &num);
result += num * 11 * (n - 1);
}
printf("%d", result);
}
1057 数零壹 (20 分)
给定一串长度不超过 105 的字符串,本题要求你将其中所有英文字母的序号(字母 a-z 对应序号 1-26,不分大小写)相加,得到整数 N,然后再分析一下 N 的二进制表示中有多少 0、多少 1。例如给定字符串 PAT (Basic)
,其字母序号之和为:16+1+20+2+1+19+9+3=71,而 71 的二进制是 1000111,即有 3 个 0、4 个 1。
输入格式:
输入在一行中给出长度不超过 105、以回车结束的字符串。
输出格式:
在一行中先后输出 0 的个数和 1 的个数,其间以空格分隔。注意:若字符串中不存在字母,则视为 N 不存在,也就没有 0 和 1。
输入样例:
PAT (Basic)
结尾无空行
输出样例:
3 4
结尾无空行
解析:
字符串判断统计输出,转换成二进制用除二取余法。
代码:
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s;
int array[2] = { 0 }, result = 0;
getline(cin, s);
for (int i = 0; i < s.size(); i++) {
if(tolower(s[i])>='a'&&tolower(s[i]) <= 'z')result+= tolower(s[i])-'\`';
}
while (result) {
array[result % 2]++;
result /= 2;
}
printf("%d %d", array[0], array[1]);
}
1058 选择题 (20 分)
批改多选题是比较麻烦的事情,本题就请你写个程序帮助老师批改多选题,并且指出哪道题错的人最多。
输入格式:
输入在第一行给出两个正整数 N(≤ 1000)和 M(≤ 100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……)
,按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。
输出格式:
按照输入的顺序给出每个学生的得分,每个分数占一行。注意判题时只有选择全部正确才能得到该题的分数。最后一行输出错得最多的题目的错误次数和编号(题目按照输入的顺序从 1 开始编号)。如果有并列,则按编号递增顺序输出。数字间用空格分隔,行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple
。
输入样例:
3 4
3 4 2 a c
2 5 1 b
5 3 2 b c
1 5 4 a b d e
(2 a c) (2 b d) (2 a c) (3 a b e)
(2 a c) (1 b) (2 a b) (4 a b d e)
(2 b d) (1 e) (2 b c) (4 a b c d)
结尾无空行
输出样例:
3
6
5
2 2 3 4
结尾无空行
1059 C语言竞赛 (20 分)
C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛。既然竞赛主旨是为了好玩,颁奖规则也就制定得很滑稽:
- 0、冠军将赢得一份“神秘大奖”(比如很巨大的一本学生研究论文集……)。
- 1、排名为素数的学生将赢得最好的奖品 —— 小黄人玩偶!
- 2、其他人将得到巧克力。
给定比赛的最终排名以及一系列参赛者的 ID,你要给出这些参赛者应该获得的奖品。
输入格式:
输入第一行给出一个正整数 N(≤104),是参赛者人数。随后 N 行给出最终排名,每行按排名顺序给出一位参赛者的 ID(4 位数字组成)。接下来给出一个正整数 K 以及 K 个需要查询的 ID。
输出格式:
对每个要查询的 ID,在一行中输出 ID: 奖品
,其中奖品或者是 Mystery Award
(神秘大奖)、或者是 Minion
(小黄人)、或者是 Chocolate
(巧克力)。如果所查 ID 根本不在排名里,打印 Are you kidding?
(耍我呢?)。如果该 ID 已经查过了(即奖品已经领过了),打印 ID: Checked
(不能多吃多占)。
输入样例:
6
1111
6666
8888
1234
5555
0001
6
8888
0001
1111
2222
8888
2222
结尾无空行
输出样例:
8888: Minion
0001: Chocolate
1111: Mystery Award
2222: Are you kidding?
8888: Checked
2222: Are you kidding?
结尾无空行
解析:
输入之后存在数组里,然后查找某个数,获得其下标,判断是第一还是素数还是其他数,获得相应的奖品。如果未查到ID,则输出相应的话。
代码:
#include <iostream>
#include <set>
#include <cmath>
using namespace std;
int ran[10000];
bool isprime(int a) {
if(a <= 1) return false;
int Sqrt = sqrt((double)a);
for(int i = 2; i <= Sqrt; i++) {
if(a % i == 0)
return false;
}
return true;
}
int main() {
int n, k;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
int id;
scanf("%d", &id);
ran[id] = i + 1;
}
scanf("%d", &k);
set<int> ss;
for(int i = 0; i < k; i++) {
int id;
scanf("%d", &id);
printf("%04d: ", id);
if(ran[id] == 0) {
printf("Are you kidding?\n");
continue;
}
if(ss.find(id) == ss.end()) {
ss.insert(id);
} else {
printf("Checked\n");
continue;
}
if(ran[id] == 1) {
printf("Mystery Award\n");
}else if(isprime(ran[id])) {
printf("Minion\n");
}else {
printf("Chocolate\n");
}
}
return 0;
}
1061 判断题 (15 分)
判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分。
输入格式:
输入在第一行给出两个不超过 100 的正整数 N 和 M,分别是学生人数和判断题数量。第二行给出 M 个不超过 5 的正整数,是每道题的满分值。第三行给出每道题对应的正确答案,0 代表“非”,1 代表“是”。随后 N 行,每行给出一个学生的解答。数字间均以空格分隔。
输出格式:
按照输入的顺序输出每个学生的得分,每个分数占一行。
输入样例:
3 6
2 1 3 3 4 5
0 0 1 0 1 1
0 1 1 0 0 1
1 0 1 0 1 0
1 1 0 0 1 1
结尾无空行
输出样例:
13
11
12
结尾无空行
解析:
简单的数组比对就好了。
代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m, num, result = 0;
scanf("%d%d", &n, &m);
vector<int> fenzhi(m),daan(m);
for (int i = 0; i < m; i++)scanf("%d", &fenzhi[i]);
for (int i = 0; i < m; i++)scanf("%d", &daan[i]);
while (n--) {
result = 0;
for (int i = 0; i < m; i++) {
scanf("%d", &num);
if (num == daan[i])result += fenzhi[i];
}
printf("%d\n", result);
}
}
1063 计算谱半径 (20 分)
在数学中,矩阵的“谱半径”是指其特征值的模集合的上确界。换言之,对于给定的 n 个复数空间的特征值 { a1+b1i,⋯,an+bni },它们的模为实部与虚部的平方和的开方,而“谱半径”就是最大模。
现在给定一些复数空间的特征值,请你计算并输出这些特征值的谱半径。
输入格式:
输入第一行给出正整数 N(≤ 10 000)是输入的特征值的个数。随后 N 行,每行给出 1 个特征值的实部和虚部,其间以空格分隔。注意:题目保证实部和虚部均为绝对值不超过 1000 的整数。
输出格式:
在一行中输出谱半径,四舍五入保留小数点后 2 位。
输入样例:
5
0 1
2 0
-1 0
3 3
0 -3
结尾无空行
解析:
仍然是简单的数学问题。
代码:
#include <iostream>
#include <math.h>
using namespace std;
int main() {
int n, a, b;
double max = -1.0;
scanf("%d", &n);
while (n--) {
scanf("%d%d", &a, &b);
if (sqrt(a*a + b * b) > max)max = sqrt(a*a + b * b);
}
printf("%.2f", max);
}
1064 朋友数 (20 分)
如果两个整数各位数字的和是一样的,则被称为是“朋友数”,而那个公共的和就是它们的“朋友证号”。例如 123 和 51 就是朋友数,因为 1+2+3 = 5+1 = 6,而 6 就是它们的朋友证号。给定一些整数,要求你统计一下它们中有多少个不同的朋友证号。
输入格式:
输入第一行给出正整数 N。随后一行给出 N 个正整数,数字间以空格分隔。题目保证所有数字小于 104。
输出格式:
首先第一行输出给定数字中不同的朋友证号的个数;随后一行按递增顺序输出这些朋友证号,数字间隔一个空格,且行末不得有多余空格。
输入样例:
8
123 899 51 998 27 33 36 12
结尾无空行
输出样例:
4
3 6 9 26
结尾无空行
解析:
这个就是简单模拟,每个位数相加就好了,选择set容器不要太方便。
代码:
#include <iostream>
#include <string>
#include <set>
using namespace std;
int main() {
int n,result;
bool flag = true;
string s;
scanf("%d", &n);
getchar();
set<int> setl;
while (n--) {
result = 0;
cin >> s;
for (int i = 0; i < s.size(); i++) result += s[i] - '0';
setl.insert(result);
}
printf("%d\n", setl.size());
set<int>::iterator it;
for (it = setl.begin(); it != setl.end(); it++) //使用迭代器进行遍历
{
if(flag)printf("%d", *it);
if (!flag)printf(" %d", *it);
flag = false;
}
}
1065 单身狗 (25 分)
“单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱。
输入格式:
输入第一行给出一个正整数 N(≤ 50 000),是已知夫妻/伴侣的对数;随后 N 行,每行给出一对夫妻/伴侣——为方便起见,每人对应一个 ID 号,为 5 位数字(从 00000 到 99999),ID 间以空格分隔;之后给出一个正整数 M(≤ 10 000),为参加派对的总人数;随后一行给出这 M 位客人的 ID,以空格分隔。题目保证无人重婚或脚踩两条船。
输出格式:
首先第一行输出落单客人的总人数;随后第二行按 ID 递增顺序列出落单的客人。ID 间用 1 个空格分隔,行的首尾不得有多余空格。
输入样例:
3
11111 22222
33333 44444
55555 66666
7
55555 44444 10000 88888 22222 11111 23333
结尾无空行
输出样例:
5
10000 23333 44444 55555 88888
结尾无空行
解析:
使用数组双向绑定,然后建立离散表查找。
代码:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main() {
int n, a, b, m;
scanf("%d", &n);
vector<int> couple(100000, -1);
for (int i = 0; i < n; i++) {
scanf("%d%d", &a, &b);
couple[a] = b;
couple[b] = a;
}
scanf("%d", &m);
vector<int> guest(m), isExist(100000);
for (int i = 0; i < m; i++) {
scanf("%d", &guest[i]);
if (couple[guest[i]] != -1)
isExist[couple[guest[i]]] = 1;
}
set<int> s;
for (int i = 0; i < m; i++) {
if (!isExist[guest[i]])
s.insert(guest[i]);
}
printf("%d\n", s.size());
for (auto it = s.begin(); it != s.end(); it++) {
if (it != s.begin()) printf(" ");
printf("%05d", *it);
}
return 0;
}
1066 图像过滤 (15 分)
图像过滤是把图像中不重要的像素都染成背景色,使得重要部分被凸显出来。现给定一幅黑白图像,要求你将灰度值位于某指定区间内的所有像素颜色都用一种指定的颜色替换。
输入格式:
输入在第一行给出一幅图像的分辨率,即两个正整数 M 和 N(0<M,N≤500),另外是待过滤的灰度值区间端点 A 和 B(0≤A<B≤255)、以及指定的替换灰度值。随后 M 行,每行给出 N 个像素点的灰度值,其间以空格分隔。所有灰度值都在 [0, 255] 区间内。
输出格式:
输出按要求过滤后的图像。即输出 M 行,每行 N 个像素灰度值,每个灰度值占 3 位(例如黑色要显示为 000
),其间以一个空格分隔。行首尾不得有多余空格。
输入样例:
3 5 100 150 0
3 189 254 101 119
150 233 151 99 100
88 123 149 0 255
结尾无空行
输出样例:
003 189 254 000 000
000 233 151 099 000
088 000 000 000 255
结尾无空行
解析:
直接输出就行,不用在另外申请数组,否则会堆栈溢出。然后按照3位前面补0的格式输出。
代码:
#include <iostream>
using namespace std;
int main() {
int m, n, a, b, it, num;
scanf("%d%d%d%d%d", &m, &n, &a, &b, &it);
for (int j = 0; j < m; j++) {
int flag = 1;
for (int i = 0; i < n; i++) {
scanf("%d", &num);
if (num >= a && num <= b)num = it;
if(flag == 1)printf("%03d", num);
if(flag == 0)printf(" %03d", num);
flag = 0;
}
printf("\n");
}
}
1069 微博转发抽奖 (20 分)
小明 PAT 考了满分,高兴之余决定发起微博转发抽奖活动,从转发的网友中按顺序每隔 N 个人就发出一个红包。请你编写程序帮助他确定中奖名单。
输入格式:
输入第一行给出三个正整数 M(≤ 1000)、N 和 S,分别是转发的总量、小明决定的中奖间隔、以及第一位中奖者的序号(编号从 1 开始)。随后 M 行,顺序给出转发微博的网友的昵称(不超过 20 个字符、不包含空格回车的非空字符串)。
注意:可能有人转发多次,但不能中奖多次。所以如果处于当前中奖位置的网友已经中过奖,则跳过他顺次取下一位。
输出格式:
按照输入的顺序输出中奖名单,每个昵称占一行。如果没有人中奖,则输出 Keep going...
。
输入样例 1:
9 3 2
Imgonnawin!
PickMe
PickMe
LookHere
Imgonnawin!
TryAgainAgain
TryAgainAgain
Imgonnawin!
TryAgainAgain
输出样例 1:
PickMe
Imgonnawin!
TryAgainAgain
输入样例 2:
2 3 5
Imgonnawin!
PickMe
输出样例 2:
Keep going...
鸣谢用户 谢成星 补充数据!
解析:
对每个数列进行跳行判断;
代码:
#include <iostream>
#include <string>
#include <set>
using namespace std;
int main() {
int m, n, s, flag = 0;
cin >> m >> n >> s;
string name[1002];
set<string> have;
for (int i = 1; i <= m; i++)cin >> name[i];
for (s; s <= m;) {
if (have.find(name[s]) == have.end()) {
cout << name[s] << "\n";
have.insert(name[s]);
s += n;
flag = 1;
}
else {
s++;
}
}
if (flag == 0)printf("Keep going...");
}
1070 结绳 (25 分)
给定一段一段的绳子,你需要把它们串成一条绳。每次串连的时候,是把两段绳子对折,再如下图所示套接在一起。这样得到的绳子又被当成是另一段绳子,可以再次对折去跟另一段绳子串连。每次串连后,原来两段绳子的长度就会减半。
给定 N 段绳子的长度,你需要找出它们能串成的绳子的最大长度。
输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出正整数 N (2≤N≤104);第 2 行给出 N 个正整数,即原始绳段的长度,数字间以空格分隔。所有整数都不超过104。
输出格式:
在一行中输出能够串成的绳子的最大长度。结果向下取整,即取为不超过最大长度的最近整数。
输入样例:
8
10 15 12 3 4 13 1 15
结尾无空行
输出样例:
14
结尾无空行
解析:
不要管题目描述的多复杂,其实就是对半相加的意思,想要最大长度,那就从最小的开始折半,这样可以使长度大的绳子折半的次数减少,减少长度损耗,所以通过排序从小到大,然后再折半相加。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n,num;
scanf("%d", &n);
vector<int> v;
for (int i = 0; i < n; i++) {
scanf("%d", &num);
v.push_back(num);
}
sort(v.begin(), v.end());
int result = (v[0] + v[1]) / 2;
for (int i = 2; i < n; i++) {
result = (result + v[i]) / 2;
}
printf("%d", result);
}
1071 小赌怡情 (15 分)
常言道“小赌怡情”。这是一个很简单的小游戏:首先由计算机给出第一个整数;然后玩家下注赌第二个整数将会比第一个数大还是小;玩家下注 t 个筹码后,计算机给出第二个数。若玩家猜对了,则系统奖励玩家 t 个筹码;否则扣除玩家 t 个筹码。
注意:玩家下注的筹码数不能超过自己帐户上拥有的筹码数。当玩家输光了全部筹码后,游戏就结束。
输入格式:
输入在第一行给出 2 个正整数 T 和 K(≤ 100),分别是系统在初始状态下赠送给玩家的筹码数、以及需要处理的游戏次数。随后 K 行,每行对应一次游戏,顺序给出 4 个数字:
n1 b t n2
其中 n1
和 n2
是计算机先后给出的两个[0, 9]内的整数,保证两个数字不相等。b
为 0 表示玩家赌小
,为 1 表示玩家赌大
。t
表示玩家下注的筹码数,保证在整型范围内。
输出格式:
对每一次游戏,根据下列情况对应输出(其中 t
是玩家下注量,x
是玩家当前持有的筹码量):
- 玩家赢,输出
Win t! Total = x.
; - 玩家输,输出
Lose t. Total = x.
; - 玩家下注超过持有的筹码量,输出
Not enough tokens. Total = x.
; - 玩家输光后,输出
Game Over.
并结束程序。
输入样例 1:
100 4
8 0 100 2
3 1 50 1
5 1 200 6
7 0 200 8
结尾无空行
输出样例 1:
Win 100! Total = 200.
Lose 50. Total = 150.
Not enough tokens. Total = 150.
Not enough tokens. Total = 150.
结尾无空行
输入样例 2:
100 4
8 0 100 2
3 1 200 1
5 1 200 6
7 0 200 8
结尾无空行
输出样例 2:
Win 100! Total = 200.
Lose 200. Total = 0.
Game Over.
结尾无空行
解析:
简单模拟
代码:
#include <iostream>
using namespace std;
int main() {
int x, k, n1, b, t, n2;
cin >> x >> k;
while (k--) {
cin >> n1 >> b >> t >> n2;
if (t > x) {
printf("Not enough tokens. Total = %d.\n", x);
continue;
}
if (b == 0 && n1 > n2 || b == 1 && n1 < n2) {
x += t;
printf("Win %d! Total = %d.\n", t, x);
}
else if (b == 0 && n1<n2 || b == 1 && n1>n2) {
x -= t;
printf("Lose %d. Total = %d.\n", t, x);
}
if (x == 0) {
printf("Game Over.\n");
break;
}
}
}
1072 开学寄语 (20 分)
下图是上海某校的新学期开学寄语:天将降大任于斯人也,必先删其微博,卸其 QQ,封其电脑,夺其手机,收其 ipad,断其 wifi,使其百无聊赖,然后,净面、理发、整衣,然后思过、读书、锻炼、明智、开悟、精进。而后必成大器也!
本题要求你写个程序帮助这所学校的老师检查所有学生的物品,以助其成大器。
输入格式:
输入第一行给出两个正整数 N(≤ 1000)和 M(≤ 6),分别是学生人数和需要被查缴的物品种类数。第二行给出 M 个需要被查缴的物品编号,其中编号为 4 位数字。随后 N 行,每行给出一位学生的姓名缩写(由 1-4 个大写英文字母组成)、个人物品数量 K(0 ≤ K ≤ 10)、以及 K 个物品的编号。
输出格式:
顺次检查每个学生携带的物品,如果有需要被查缴的物品存在,则按以下格式输出该生的信息和其需要被查缴的物品的信息(注意行末不得有多余空格):
姓名缩写: 物品编号1 物品编号2 ……
最后一行输出存在问题的学生的总人数和被查缴物品的总数。
输入样例:
4 2
2333 6666
CYLL 3 1234 2345 3456
U 4 9966 6666 8888 6666
GG 2 2333 7777
JJ 3 0012 6666 2333
结尾无空行
输出样例:
U: 6666 6666
GG: 2333
JJ: 6666 2333
3 5
结尾无空行
解析:
本质也是每一项检查然后判断输出,最后注意输出格式。
代码:
#include <iostream>
#include <string>
#include <set>
using namespace std;
int main() {
int n, m, k, code, bcode, flag = 0, stunum = 0, objnum = 0;
set<int> s;
string name;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
scanf("%d", &bcode);
s.insert(bcode);
}
while (n--) {
cin >> name >> k;
flag = 0;
for (int i = 0; i < k; i++) {
scanf("%d", &code);
if (s.find(code) != s.end()) {
if (flag == 0) {
cout << name << ":";
flag = 1;
stunum++;
}
printf(" %04d", code);
objnum++;
}
}
if(flag != 0)printf("\n");
}
printf("%d %d", stunum, objnum);
}
1073 多选题常见计分法 (20 分)
批改多选题是比较麻烦的事情,有很多不同的计分方法。有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 50% 分数;如果考生选择了任何一个错误的选项,则不能得分。本题就请你写个程序帮助老师批改多选题,并且指出哪道题的哪个选项错的人最多。
输入格式:
输入在第一行给出两个正整数 N(≤1000)和 M(≤100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……)
,按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。
输出格式:
按照输入的顺序给出每个学生的得分,每个分数占一行,输出小数点后 1 位。最后输出错得最多的题目选项的信息,格式为:错误次数 题目编号(题目按照输入的顺序从1开始编号)-选项号
。如果有并列,则每行一个选项,按题目编号递增顺序输出;再并列则按选项号递增顺序输出。行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple
。
输入样例 1:
3 4
3 4 2 a c
2 5 1 b
5 3 2 b c
1 5 4 a b d e
(2 a c) (3 b d e) (2 a c) (3 a b e)
(2 a c) (1 b) (2 a b) (4 a b d e)
(2 b d) (1 e) (1 c) (4 a b c d)
结尾无空行
输出样例 1:
3.5
6.0
2.5
2 2-e
2 3-a
2 3-b
结尾无空行
输入样例 2:
2 2
3 4 2 a c
2 5 1 b
(2 a c) (1 b)
(2 a c) (1 b)
结尾无空行
输出样例 2:
5.0
5.0
Too simple
结尾无空行
解析:
1075 链表元素分类 (25 分)
给定一个单链表,请编写程序将链表元素进行分类排列,使得所有负值元素都排在非负值元素的前面,而 [0, K] 区间内的元素都排在大于 K 的元素前面。但每一类内部元素的顺序是不能改变的。例如:给定链表为 18→7→-4→0→5→-6→10→11→-2,K 为 10,则输出应该为 -4→-6→-2→7→0→5→10→18→11。
输入格式:
每个输入包含一个测试用例。每个测试用例第 1 行给出:第 1 个结点的地址;结点总个数,即正整数N (≤105);以及正整数K (≤103)。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。
接下来有 N 行,每行格式为:
Address Data Next
其中 Address
是结点地址;Data
是该结点保存的数据,为 [−105,105] 区间内的整数;Next
是下一结点的地址。题目保证给出的链表不为空。
输出格式:
对每个测试用例,按链表从头到尾的顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。
输入样例:
00100 9 10
23333 10 27777
00000 0 99999
00100 18 12309
68237 -6 23333
33218 -4 00000
48652 -2 -1
99999 5 68237
27777 11 48652
12309 7 33218
结尾无空行
输出样例:
33218 -4 68237
68237 -6 48652
48652 -2 12309
12309 7 00000
00000 0 99999
99999 5 23333
23333 10 00100
00100 18 27777
27777 11 -1
结尾无空行
解析:
用vector三个数组去设计
代码:
#include <iostream>
#include <vector>
using namespace std;
struct node {
int data, next;
}list[100000];
vector<int> v[3];
int main() {
int start, n, k, a;
scanf("%d%d%d", &start, &n, &k);
for (int i = 0; i < n; i++) {
scanf("%d", &a);
scanf("%d%d", &list[a].data, &list[a].next);
}
int p = start;
while (p != -1) {
int data = list[p].data;
if (data < 0)
v[0].push_back(p);
else if (data >= 0 && data <= k)
v[1].push_back(p);
else
v[2].push_back(p);
p = list[p].next;
}
int flag = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < v[i].size(); j++) {
if (flag == 0) {
printf("%05d %d ", v[i][j], list[v[i][j]].data);
flag = 1;
}
else {
printf("%05d\n%05d %d ", v[i][j], v[i][j], list[v[i][j]].data);
}
}
}
printf("-1");
return 0;
}
1076 Wifi密码 (15 分)
下面是微博上流传的一张照片:“各位亲爱的同学们,鉴于大家有时需要使用 wifi,又怕耽误亲们的学习,现将 wifi 密码设置为下列数学题答案:A-1;B-2;C-3;D-4;请同学们自己作答,每两日一换。谢谢合作!!~”—— 老师们为了促进学生学习也是拼了…… 本题就要求你写程序把一系列题目的答案按照卷子上给出的对应关系翻译成 wifi 的密码。这里简单假设每道选择题都有 4 个选项,有且只有 1 个正确答案。
输入格式:
输入第一行给出一个正整数 N(≤ 100),随后 N 行,每行按照 编号-答案
的格式给出一道题的 4 个选项,T
表示正确选项,F
表示错误选项。选项间用空格分隔。
输出格式:
在一行中输出 wifi 密码。
输入样例:
8
A-T B-F C-F D-F
C-T B-F A-F D-F
A-F D-F C-F B-T
B-T A-F C-F D-F
B-F D-T A-F C-F
A-T C-F B-F D-F
D-T B-F C-F A-F
C-T A-F B-F D-F
结尾无空行
输出样例:
13224143
结尾无空行
解析:
可以用数组的方式,也可以用字符串的方式去解决,可以用switch语句,也可以用哈希表,这里我采用字符串的方式去解决。下面更强的代码可以体现出输入未必是一行,可以分解为原子输入。
代码:
#include <iostream>
#include <string>
using namespace std;
int main() {
int n;
char array[5] = { '0','1','2','3','4' };
string s;
scanf("%d", &n);
getchar();
while(n){
getline(cin, s);
int i = s.find('T');
char c = s[i - 2];
printf("%c", array[c - '@']);
n--;
}
}
更高级代码:
#include <iostream>
using namespace std;
int main() {
string s;
while (cin >> s)
if(s.size() == 3 && s[2] == 'T') cout << s[0]-'A'+1;
return 0;
}
1077 互评成绩计算 (20 分)
在浙大的计算机专业课中,经常有互评分组报告这个环节。一个组上台介绍自己的工作,其他组在台下为其表现评分。最后这个组的互评成绩是这样计算的:所有其他组的评分中,去掉一个最高分和一个最低分,剩下的分数取平均分记为 G1;老师给这个组的评分记为 G2。该组得分为 (G1+G2)/2,最后结果四舍五入后保留整数分。本题就要求你写个程序帮助老师计算每个组的互评成绩。
输入格式:
输入第一行给出两个正整数 N(> 3)和 M,分别是分组数和满分,均不超过 100。随后 N 行,每行给出该组得到的 N 个分数(均保证为整型范围内的整数),其中第 1 个是老师给出的评分,后面 N−1 个是其他组给的评分。合法的输入应该是 [0,M] 区间内的整数,若不在合法区间内,则该分数须被忽略。题目保证老师的评分都是合法的,并且每个组至少会有 3 个来自同学的合法评分。
输出格式:
为每个组输出其最终得分。每个得分占一行。
输入样例:
6 50
42 49 49 35 38 41
36 51 50 28 -1 30
40 36 41 33 47 49
30 250 -25 27 45 31
48 0 0 50 50 1234
43 41 36 29 42 29
结尾无空行
输出样例:
42
33
41
31
37
39
结尾无空行
解析:
针对数组的处理。和模拟的简单计算。
代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int n, m, source, g2;
double g1 = 0, result;
vector<int> v;
scanf("%d%d", &n, &m);
int k = n;
while (k--) {
int t = n - 1;
g1 = 0;
scanf("%d", &g2);
while (t--) {
scanf("%d", &source);
if (source >= 0 && source <= m)v.push_back(source);
}
sort(v.begin(), v.end());
for (int i = 1; i < v.size() - 1; i++)g1 += v[i];
g1 = g1 / (v.size() - 2);
v.clear();
result = round((g1 + g2) / 2);
printf("%d\n", (int)result);
}
return 0;
}
1078 字符串压缩与解压 (20 分)
文本压缩有很多种方法,这里我们只考虑最简单的一种:把由相同字符组成的一个连续的片段用这个字符和片段中含有这个字符的个数来表示。例如 ccccc
就用 5c
来表示。如果字符没有重复,就原样输出。例如 aba
压缩后仍然是 aba
。
解压方法就是反过来,把形如 5c
这样的表示恢复为 ccccc
。
本题需要你根据压缩或解压的要求,对给定字符串进行处理。这里我们简单地假设原始字符串是完全由英文字母和空格组成的非空字符串。
输入格式:
输入第一行给出一个字符,如果是 C
就表示下面的字符串需要被压缩;如果是 D
就表示下面的字符串需要被解压。第二行给出需要被压缩或解压的不超过 1000 个字符的字符串,以回车结尾。题目保证字符重复个数在整型范围内,且输出文件不超过 1MB。
输出格式:
根据要求压缩或解压字符串,并在一行中输出结果。
输入样例 1:
C
TTTTThhiiiis isssss a tesssst CAaaa as
结尾无空行
输出样例 1:
5T2h4is i5s a3 te4st CA3a as
结尾无空行
输入样例 2:
D
5T2h4is i5s a3 te4st CA3a as10Z
结尾无空行
输出样例 2:
TTTTThhiiiis isssss a tesssst CAaaa asZZZZZZZZZZ
结尾无空行
解析:
分别写一个压缩函数和解压函数,对字符串的数值进行判断。
代码:
#include <iostream>
#include <string>
using namespace std;
string s;
void press() {
getline(cin, s);
int j = 0,i = 0;
for (i = 0; i < s.size(); i = j) {
for (j = i; j < s.size(); j++) {
if (s[i] != s[j] && (j - i) > 1) {
cout << j - i << s[i];
break;
}
else if (s[i] != s[j] && (j - i) == 1) {
cout << s[i];
break;
}
else if (j == s.size() - 1) {
if (j - i > 0)cout << j - i + 1 << s[j];
if (j - i == 0)cout << s[j];
}
}
}
}
void unpress() {
string num;
int cnt;
getline(cin, s);
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0'&&s[i] <= '9') {
num += s[i];
}
else {
if (num.length() > 0) cnt = stoi(num);
for (int j = 0; j < cnt; j++)cout << s[i];
cnt = 1;
num = "";
}
}
}
int main() {
char c;
cin >> c;
getchar();
if (c == 'C') {
press();
}
else if (c == 'D') {
unpress();
}
}
1079 延迟的回文数 (20 分)
给定一个 k+1 位的正整数 N,写成 ak⋯a1a0 的形式,其中对所有 i 有 0≤ai<10 且 ak>0。N 被称为一个回文数,当且仅当对所有 i 有 ai=ak−i。零也被定义为一个回文数。
非回文数也可以通过一系列操作变出回文数。首先将该数字逆转,再将逆转数与该数相加,如果和还不是一个回文数,就重复这个逆转再相加的操作,直到一个回文数出现。如果一个非回文数可以变出回文数,就称这个数为延迟的回文数。(定义翻译自 en.wikipedia.org/wiki/Palind… )
给定任意一个正整数,本题要求你找到其变出的那个回文数。
输入格式:
输入在一行中给出一个不超过1000位的正整数。
输出格式:
对给定的整数,一行一行输出其变出回文数的过程。每行格式如下
A + B = C
其中 A
是原始的数字,B
是 A
的逆转数,C
是它们的和。A
从输入的整数开始。重复操作直到 C
在 10 步以内变成回文数,这时在一行中输出 C is a palindromic number.
;或者如果 10 步都没能得到回文数,最后就在一行中输出 Not found in 10 iterations.
。
输入样例 1:
97152
结尾无空行
输出样例 1:
97152 + 25179 = 122331
122331 + 133221 = 255552
255552 is a palindromic number.
结尾无空行
输入样例 2:
196
结尾无空行
输出样例 2:
196 + 691 = 887
887 + 788 = 1675
1675 + 5761 = 7436
7436 + 6347 = 13783
13783 + 38731 = 52514
52514 + 41525 = 94039
94039 + 93049 = 187088
187088 + 880781 = 1067869
1067869 + 9687601 = 10755470
10755470 + 07455701 = 18211171
Not found in 10 iterations.
结尾无空行
解析:
用reverse函数解决回文问题
代码:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string add(string s1, string s2) {
string s = s1;
int carry = 0;
for (int i = s1.size() - 1; i >= 0; i--) {
s[i] = (s1[i] - '0' + s2[i] - '0' + carry) % 10 + '0';
carry = (s1[i] - '0' + s2[i] - '0' + carry) / 10;
}
if (carry > 0) s = "1" + s;
return s;
}
int main() {
string s, r, c;
int flag = 0, k = 10;
getline(cin, s);
while (k--) {
r = s;
reverse(s.begin(), s.end());
if (r == s) {
cout << s << " is a palindromic number.\n";
return 0;
}
c = add(r, s);
cout << r << " + " << s << " = " << c << "\n";
r = c;
s = r;
reverse(r.begin(), r.end());
if (s == r) {
cout << c << " is a palindromic number.";
flag = 1;
break;
}
}
i1080 MOOC期终成绩 (25 分)f(flag==0)printf("Not found in 10 iterations.");
}
1080 MOOC期终成绩 (25 分)
对于在中国大学MOOC(www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,必须首先获得不少于200分的在线编程作业分,然后总评获得不少于60分(满分100)。总评成绩的计算公式为 G=(Gmid−term×40%+Gfinal×60%),如果 Gmid−term>Gfinal;否则总评 G 就是 Gfinal。这里 Gmid−term 和 Gfinal 分别为学生的期中和期末成绩。
现在的问题是,每次考试都产生一张独立的成绩单。本题就请你编写程序,把不同的成绩单合为一张。
输入格式:
输入在第一行给出3个整数,分别是 P(做了在线编程作业的学生数)、M(参加了期中考试的学生数)、N(参加了期末考试的学生数)。每个数都不超过10000。
接下来有三块输入。第一块包含 P 个在线编程成绩 Gp;第二块包含 M 个期中考试成绩 Gmid−term;第三块包含 N 个期末考试成绩 Gfinal。每个成绩占一行,格式为:学生学号 分数
。其中学生学号
为不超过20个字符的英文字母和数字;分数
是非负整数(编程总分最高为900分,期中和期末的最高分为100分)。
输出格式:
打印出获得合格证书的学生名单。每个学生占一行,格式为:
学生学号
Gp Gmid−term Gfinal G
如果有的成绩不存在(例如某人没参加期中考试),则在相应的位置输出“−1”。输出顺序为按照总评分数(四舍五入精确到整数)递减。若有并列,则按学号递增。题目保证学号没有重复,且至少存在1个合格的学生。
输入样例:
6 6 7
01234 880
a1903 199
ydjh2 200
wehu8 300
dx86w 220
missing 400
ydhfu77 99
wehu8 55
ydjh2 98
dx86w 88
a1903 86
01234 39
ydhfu77 88
a1903 66
01234 58
wehu8 84
ydjh2 82
missing 99
dx86w 81
结尾无空行
输出样例:
missing 400 -1 99 99
ydjh2 200 98 82 88
dx86w 220 88 81 84
wehu8 300 55 84 84
结尾无空行
解析:
要分三种情况设计程序。用vector进行分类。
代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
using namespace std;
struct node {
string name;
int gp, gm, gf, g;
};
bool cmp(node a, node b) {
return a.g != b.g ? a.g > b.g : a.name < b.name;
}
map<string, int> idx;
int main() {
int p, m, n, score, cnt = 1;
cin >> p >> m >> n;
vector<node> v, ans;
string s;
for (int i = 0; i < p; i++) {
cin >> s >> score;
if (score >= 200) {
v.push_back(node{ s, score, -1, -1, 0 });
idx[s] = cnt++;
}
}
for (int i = 0; i < m; i++) {
cin >> s >> score;
if (idx[s] != 0) v[idx[s] - 1].gm = score;
}
for (int i = 0; i < n; i++) {
cin >> s >> score;
if (idx[s] != 0) {
int temp = idx[s] - 1;
v[temp].gf = v[temp].g = score;
if (v[temp].gm > v[temp].gf) v[temp].g = int(v[temp].gm * 0.4 + v[temp].gf * 0.6 + 0.5);
}
}
for (int i = 0; i < v.size(); i++)
if (v[i].g >= 60) ans.push_back(v[i]);
sort(ans.begin(), ans.end(), cmp);
for (int i = 0; i < ans.size(); i++)
printf("%s %d %d %d %d\n", ans[i].name.c_str(), ans[i].gp, ans[i].gm, ans[i].gf, ans[i].g);
return 0;
}
1082 射击比赛 (20 分)
本题目给出的射击比赛的规则非常简单,谁打的弹洞距离靶心最近,谁就是冠军;谁差得最远,谁就是菜鸟。本题给出一系列弹洞的平面坐标(x,y),请你编写程序找出冠军和菜鸟。我们假设靶心在原点(0,0)。
输入格式:
输入在第一行中给出一个正整数 N(≤ 10 000)。随后 N 行,每行按下列格式给出:
ID x y
其中 ID
是运动员的编号(由 4 位数字组成);x
和 y
是其打出的弹洞的平面坐标(x
,y
),均为整数,且 0 ≤ |x
|, |y
| ≤ 100。题目保证每个运动员的编号不重复,且每人只打 1 枪。
输出格式:
输出冠军和菜鸟的编号,中间空 1 格。题目保证他们是唯一的。
输入样例:
3
0001 5 7
1020 -1 3
0233 0 -1
结尾无空行
输出样例:
0233 0001
结尾无空行
解析:
勾股定理冲!
代码:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n, maxcode, mincode, code, x, y;
float maxsource = -1, minsource = 101, result;
scanf("%d", &n);
while (n--) {
scanf("%d%d%d", &code, &x, &y);
result = sqrt(x * x + y * y);
if (result > maxsource) {
maxcode = code;
maxsource = result;
}
else if (result < minsource) {
mincode = code;
minsource = result;
}
}
printf("%04d %04d", mincode, maxcode);
}
1083 是否存在相等的差 (20 分)
给定 N 张卡片,正面分别写上 1、2、……、N,然后全部翻面,洗牌,在背面分别写上 1、2、……、N。将每张牌的正反两面数字相减(大减小),得到 N 个非负差值,其中是否存在相等的差?
输入格式:
输入第一行给出一个正整数 N(2 ≤ N ≤ 10 000),随后一行给出 1 到 N 的一个洗牌后的排列,第 i 个数表示正面写了 i 的那张卡片背面的数字。
输出格式:
按照“差值 重复次数”的格式从大到小输出重复的差值及其重复的次数,每行输出一个结果。
输入样例:
8
3 5 8 6 2 1 4 7
结尾无空行
输出样例:
5 2
3 3
2 2
结尾无空行
解析:
计算差值绝对值,统计重复次数,选对STL容器
代码:
#include <iostream>
#include <cmath>
#include <map>
using namespace std;
int main() {
int n,num;
map<int,int,greater<int>> m;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &num);
++m[abs(num - i)];
}
map<int, int>::iterator it;
for (it = m.begin(); it != m.end(); it++) {
if(it->second>1)cout << it->first << " " << it->second << "\n";
}
}
1084 外观数列 (20 分)
外观数列是指具有以下特点的整数序列:
d, d1, d111, d113, d11231, d112213111, ...
它从不等于 1 的数字 d
开始,序列的第 n+1 项是对第 n 项的描述。比如第 2 项表示第 1 项有 1 个 d
,所以就是 d1
;第 2 项是 1 个 d
(对应 d1
)和 1 个 1(对应 11),所以第 3 项就是 d111
。又比如第 4 项是 d113
,其描述就是 1 个 d
,2 个 1,1 个 3,所以下一项就是 d11231
。当然这个定义对 d
= 1 也成立。本题要求你推算任意给定数字 d
的外观数列的第 N 项。
输入格式:
输入第一行给出 [0,9] 范围内的一个整数 d
、以及一个正整数 N(≤ 40),用空格分隔。
输出格式:
在一行中给出数字 d
的外观数列的第 N 项。
输入样例:
1 8
结尾无空行
输出样例:
1123123111
结尾无空行
解析:
用两个指针去做跳动和遍历
代码:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
int n, j;
cin >> s >> n;
for (int cnt = 1; cnt < n; cnt++) {
string t;
for (int i = 0; i < s.length(); i = j) {
for (j = i; j < s.length() && s[j] == s[i]; j++);
t += s[i] + to_string(j - i);
}
s = t;
}
cout << s;
return 0;
}
1086 就不告诉你 (15 分)
做作业的时候,邻座的小盆友问你:“五乘以七等于多少?”你应该不失礼貌地围笑着告诉他:“五十三。”本题就要求你,对任何一对给定的正整数,倒着输出它们的乘积。
输入格式:
输入在第一行给出两个不超过 1000 的正整数 A 和 B,其间以空格分隔。
输出格式:
在一行中倒着输出 A 和 B 的乘积。
输入样例:
5 7
结尾无空行
输出样例:
53
结尾无空行
解析:
转置之后输出,且注意前面为0不输出。所以按整形输出。
代码:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
int a, b;
string s;
cin >> a >> b;
s = to_string(a*b);
reverse(s.begin(), s.end());
printf("%d", stoi(s));
}
1087 有多少不同的值 (20 分)
当自然数 n 依次取 1、2、3、……、N 时,算式 ⌊n/2⌋+⌊n/3⌋+⌊n/5⌋ 有多少个不同的值?(注:⌊x⌋ 为取整函数,表示不超过 x 的最大自然数,即 x 的整数部分。)
输入格式:
输入给出一个正整数 N(2≤N≤104)。
输出格式:
在一行中输出题面中算式取到的不同值的个数。
输入样例:
2017
结尾无空行
输出样例:
1480
结尾无空行
解析:
这里就是遍历每个数,然后去计算值,不可重复的数。我采用了散列表的方法去统计,而更简便的方法是采用了STL库中的set容器,因为set容器本身有不会重复插入的特性,所以很好的计算了不重复的个数。
代码:
#include <iostream>
using namespace std;
int main() {
int n, array[100000] = {0}, sum = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int pos = i / 2 + i / 3 + i / 5;
if (array[pos] == 0) {
array[pos]++;
sum++;
}
}
printf("%d", sum);
}
更高级代码:
#include <iostream>
#include <set>
using namespace std;
int main() {
int n;
scanf("%d", &n);
set<int> s;
for (int i = 1; i <= n; i++)
s.insert(i / 2 + i / 3 + i / 5);
printf("%d", s.size());
return 0;
}
虽然在代码行数上没有太大差别,但后者的代码更具有封装性简洁性,很好运用了stl库里封装的工具。
1089 狼人杀-简单版 (20 分)
以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说:“4 号是狼人”,4 号玩家说:“5 号是好人”,5 号玩家说:“4 号是好人”。已知这 5 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。扮演狼人角色的是哪两号玩家?
本题是这个问题的升级版:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?
输入格式:
输入在第一行中给出一个正整数 N(5≤N≤100)。随后 N 行,第 i 行给出第 i 号玩家说的话(1≤i≤N),即一个玩家编号,用正号表示好人,负号表示狼人。
输出格式:
如果有解,在一行中按递增顺序输出 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 A=a[1],...,a[M] 和 B=b[1],...,b[M],若存在 0≤k<M 使得 a[i]=b[i] (i≤k),且 a[k+1]<b[k+1],则称序列 A 小于序列 B。若无解则输出 No Solution
。
输入样例 1:
5
-2
+3
-4
+5
+4
结尾无空行
输出样例 1:
1 4
结尾无空行
输入样例 2:
6
+6
+3
+1
-5
-2
+4
结尾无空行
输出样例 2(解不唯一):
1 5
结尾无空行
输入样例 3:
5
-2
-3
-4
-5
-1
结尾无空行
输出样例 3:
No Solution
结尾无空行
解析(柳神):
每个人说的数字保存在v数组中,i从1~n、j从i+1~n遍历,分别假设i和j是狼人,a数组表示该人是狼人还是好人,等于1表示是好人,等于-1表示是狼人。k从1~n分别判断k所说的话是真是假,k说的话和真实情况不同(即v[k] * a[abs(v[k])] < 0)则表示k在说谎,则将k放在lie数组中;遍历完成后判断lie数组,如果说谎人数等于2并且这两个说谎的人一个是好人一个是狼人(即a[lie[0]] + a[lie[1]] == 0)表示满足题意,此时输出i和j并return,否则最后的时候输出No Solution
代码(柳神):
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> v(n + 1);
for (int i = 1; i <= n; i++)cin >> v[i];
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
vector<int> lie, a(n + 1, 1);
a[i] = a[j] = -1;
for (int k = 1; k <= n; k++)
if (v[k] * a[abs(v[k])] < 0)lie.push_back(k);
if (lie.size() == 2 && a[lie[0]] + a[lie[1]] == 0) {
cout << i << " " << j;
return 0;
}
}
}
}
这个方法实在是太巧妙了,我想不出来呜呜呜。
1090 危险品装箱 (25 分)
集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸。
本题给定一张不相容物品的清单,需要你检查每一张集装箱货品清单,判断它们是否能装在同一只箱子里。
输入格式:
输入第一行给出两个正整数:N (≤104) 是成对的不相容物品的对数;M (≤100) 是集装箱货品清单的单数。
随后数据分两大块给出。第一块有 N 行,每行给出一对不相容的物品。第二块有 M 行,每行给出一箱货物的清单,格式如下:
K G[1] G[2] ... G[K]
其中 K
(≤1000) 是物品件数,G[i]
是物品的编号。简单起见,每件物品用一个 5 位数的编号代表。两个数字之间用空格分隔。
输出格式:
对每箱货物清单,判断是否可以安全运输。如果没有不相容物品,则在一行中输出 Yes
,否则输出 No
。
输入样例:
6 3
20001 20002
20003 20004
20005 20006
20003 20001
20005 20004
20004 20006
4 00001 20004 00002 20003
5 98823 20002 20003 20006 10010
3 12345 67890 23333
结尾无空行
输出样例:
No
Yes
Yes
结尾无空行
解析:
这道题和1051是一个意思。
代码:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main() {
int n, k, t1, t2;
map<int, vector<int>> m;
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++) {
scanf("%d%d", &t1, &t2);
m[t1].push_back(t2);
m[t2].push_back(t1);
}
while (k--) {
int cnt, flag = 0, a[100000] = { 0 };
scanf("%d", &cnt);
vector<int> v(cnt);
for (int i = 0; i < cnt; i++) {
scanf("%d", &v[i]);
a[v[i]] = 1;
}
for (int i = 0; i < v.size(); i++)
for (int j = 0; j < m[v[i]].size(); j++)
if (a[m[v[i]][j]] == 1) flag = 1;
printf("%s\n", flag ? "No" : "Yes");
}
return 0;
}
1091 N-自守数 (15 分)
如果某个数 K 的平方乘以 N 以后,结果的末尾几位数等于 K,那么就称这个数为“N-自守数”。例如 3×922=25392,而 25392 的末尾两位正好是 92,所以 92 是一个 3-自守数。
本题就请你编写程序判断一个给定的数字是否关于某个 N 是 N-自守数。
输入格式:
输入在第一行中给出正整数 M(≤20),随后一行给出 M 个待检测的、不超过 1000 的正整数。
输出格式:
对每个需要检测的数字,如果它是 N-自守数就在一行中输出最小的 N 和 NK2 的值,以一个空格隔开;否则输出 No
。注意题目保证 N<10。
输入样例:
3
92 5 233
结尾无空行
输出样例:
3 25392
1 25
No
结尾无空行
解析:
做字符串的截取即可。
代码:
#include <iostream>
#include <string>
using namespace std;
int main() {
int m, k, flag = 0;
string s;
scanf("%d", &m);
while (m--) {
flag = 0;
scanf("%d", &k);
for (int i = 1; i < 10; i++) {
s = to_string(i * k * k);
string send = s.substr(s.length() - to_string(k).size());
if (send == to_string(k)) {
cout << i << " " << s << "\n";
flag = 1;
break;
}
}
if (flag == 0)cout << "No" << "\n";
}
}
1092 最好吃的月饼 (20 分)
月饼是久负盛名的中国传统糕点之一,自唐朝以来,已经发展出几百品种。
若想评比出一种“最好吃”的月饼,那势必在吃货界引发一场腥风血雨…… 在这里我们用数字说话,给出全国各地各种月饼的销量,要求你从中找出销量冠军,认定为最好吃的月饼。
输入格式:
输入首先给出两个正整数 N(≤1000)和 M(≤100),分别为月饼的种类数(于是默认月饼种类从 1 到 N 编号)和参与统计的城市数量。
接下来 M 行,每行给出 N 个非负整数(均不超过 1 百万),其中第 i 个整数为第 i 种月饼的销量(块)。数字间以空格分隔。
输出格式:
在第一行中输出最大销量,第二行输出销量最大的月饼的种类编号。如果冠军不唯一,则按编号递增顺序输出并列冠军。数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
5 3
1001 992 0 233 6
8 0 2018 0 2008
36 18 0 1024 4
结尾无空行
输出样例:
2018
3 5
结尾无空行
解析:
寻找最大值输出:
代码:
#include <iostream>
using namespace std;
int main() {
int n, m, source, maxsource = -1, mooncake, array[1001] = {0}, flag = 0;
scanf("%d%d", &n, &m);
int t = m;
while (t--) {
for (int i = 0; i < n; i++) {
scanf("%d", &source);
array[i] += source;
if (array[i] > maxsource)maxsource = array[i];
}
}
printf("%d\n", maxsource);
for (int i = 0; i < n; i++) {
if (array[i] == maxsource) {
if (flag == 0)printf("%d", i + 1);
if (flag == 1)printf(" %d", i+1);
flag = 1;
}
}
}
1093 字符串A+B (20 分)
给定两个字符串 A 和 B,本题要求你输出 A+B,即两个字符串的并集。要求先输出 A,再输出 B,但重复的字符必须被剔除。
输入格式:
输入在两行中分别给出 A 和 B,均为长度不超过 106的、由可见 ASCII 字符 (即码值为32~126)和空格组成的、由回车标识结束的非空字符串。
输出格式:
在一行中输出题面要求的 A 和 B 的和。
输入样例:
This is a sample test
to show you_How it works
结尾无空行
输出样例:
This ampletowyu_Hrk
结尾无空行
解析:
不重复输出即可
代码:
#include <iostream>
#include <string>
using namespace std;
int main() {
int array[130] = { 0 };
string a, b;
getline(cin, a);
getline(cin, b);
for (int i = 0; i < a.size(); i++) {
if (array[a[i]] == 0) {
printf("%c", a[i]);
array[a[i]]++;
}
}
for (int i = 0; i < b.size(); i++) {
if (array[b[i]] == 0) {
printf("%c", b[i]);
array[b[i]]++;
}
}
}