202509-1 数组清零
题目描述
小 A 有一个由 个非负整数构成的数组 。他会对阵组 重复进行以下操作,直到数组 只包含 0。在一次操作中,小 A 会依次完成以下三个步骤:
- 在数组 中找到最大的整数,记其下标为 。如果有多个最大值,那么选择其中下标最大的。
- 从数组 所有不为零的整数中找到最小的整数 。
- 将第一步找出的 减去 。
例如,数组 需要 7 次操作变成 :
小 A 想知道,对于给定的数组 ,需要多少次操作才能使得 中的整数全部变成 0。可以证明, 中整数必然可以在有限次操作后全部变成 0。你能帮他计算出答案吗?
输入格式
第一行,一个正整数 ,表示数组 的长度。
第二行, 个非负整数 ,表示数组 中的整数。
输出格式
一行,一个正整数,表示 中整数全部变成 0 所需要的操作次数。
样例输入 1
32 3 4
样例输出 1
7
样例输入 2
51 3 2 2 5
样例输出 2
13
提示
对于所有测试点,保证 ,。
代码解析
这道题题目不难,主要考察的是打擂台求最大值和最小值,判断数组全部为0可以换种思路,如果数组的最大值是0,那数组元素肯定全部都是0。
#include<bits/stdc++.h>using namespace std;int main() {
int a[105], n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; int cnt = 0; while (1) { int k = 1, aj = 999; for (int i = 1; i <= n; i++) { if (a[i] != 0) aj = min(aj, a[i]); // 这里使用 >= 保证有多个最大值选下标最大的 if (a[i] >= a[k]) k = i; } // 如果最大值是 0 说明已经全都是 0 了 if (a[k] == 0) break; a[k] -= aj; cnt++; } cout << cnt;
return 0;}
202509-2 日历制作
题目描述
小 A 想制作 年每个月的日历。他希望你能编写一个程序,按照格式输出给定月份的日历。
具体来说,第一行需要输出 MON TUE WED THU FRI SAT SUN,分别表示星期一到星期日。接下来若干行中依次输出这个月所包含的日期,日期的个位需要和对应星期几的缩写最后一个字母对齐。例如, 年 月 日是星期一,在输出九月的日历时, 号的个位 就需要与星期一 MON 的最后一个字母 N 对齐。九月的日历输出效果如下:
MON TUE WED THU FRI SAT SUN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
你能帮助小 A 完成日历的制作吗?
输入格式
一行,一个正整数 ,表示需要按照格式输出 年 月的日历。
输出格式
输出包含若干行,表示 年 月的日历。
样例输入 1
9
样例输出 1
MON TUE WED THU FRI SAT SUN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
样例输入 2
6
样例输出 2
MON TUE WED THU FRI SAT SUN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
提示
对于所有测试点,保证 。
代码解析
这道题目给出了 9 月 1 日是星期一,所以其他月的 1 号是星期几需要从 9 月开始往前或者往后去推,推出来这个月的 1 号是星期几之后剩下的就简单了。
#include<bits/stdc++.h>using namespace std;int main() {
int m; int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; cin >> m;
int sum = 0; if (m >= 9) { // 往后推 1 号是周几 for (int i = 9; i < m; i++) sum += days[i]; sum = sum % 7; } else { // 往前推 1 号是周几 for (int i = 8; i >= m; i--) sum += days[i]; sum = 7 - sum % 7; }
cout << "MON TUE WED THU FRI SAT SUN" << endl; // 输出前面的空格 for (int i = 1; i <= sum; i++) cout << " "; for (int i = 1; i <= days[m]; i++) { if (i < 10) cout << " "; else cout << ' '; cout << i << ' '; // 换行需要考虑到前面空格的数量 if ((i+sum) % 7 == 0) cout << endl; }
return 0;}
202506-1 奇偶校验
题目描述
数据在传输过程中可能出错,因此接收方收到数据后通常会校验传输的数据是否正确,奇偶校验是经典的校验方式之一。
给定 个非负整数 代表所传输的数据,它们的校验码取决于这些整数在二进制下 1 的数量 之和的奇偶性。如果这些整数在二进制下共有奇数个 1,那么校验码为 1;否则校验码为 0。你能求出这些整数的校验码吗?
输入格式
第一行,一个正整数 ,表示所传输的数据量。
第二行, 个非负整数 ,表示所传输的数据。
输出格式
输出一行,两个整数,以一个空格分隔:
第一个整数表示 在二进制下 1 的总数量;
第二个整数表示校验码(0 或 1)。
样例输入 1
471 69 83 80
样例输出 1
13 1
样例输入 2
61 2 4 8 16 32
样例输出 2
6 0
提示
对于所有测试点,保证 ,。
代码解析
题目意思很好理解,需要统计 n 个数字中,每个数字的二进制中 1 的个数的和,并且判断 1 的个数是奇数还是偶数,使用二进制的数位剥离方法即可。
#include<bits/stdc++.h>using namespace std;int main() {
int n, cnt = 0; cin >> n; while (n--) { int c; cin >> c; while (c) { cnt += c % 2; c /= 2; } } cout << cnt << ' ' << cnt % 2;
return 0;}
202506-2 分糖果
题目描述
有 位小朋友排成一队等待老师分糖果。第 位小朋友想要至少 颗糖果,并且分给他的糖果数量必须比分给 前一位小朋友的糖果数量更多,不然他就会不开心。
老师想知道至少需要准备多少颗糖果才能让所有小朋友都开心。你能帮帮老师吗?
输入格式
第一行,一个正整数 ,表示小朋友的人数。
第二行, 个正整数 ,依次表示每位小朋友至少需要的糖果数量。
输出格式
输出一行,一个整数,表示最少需要准备的糖果数量。
样例输入 1
41 4 3 3
样例输出 1
16
样例输入 2
15314 15926 53589793 238462643 383279502 8 8 4 1 9 7 1 6 9 3
样例输出 2
4508143253
提示
对于所有测试点,保证 ,。
代码解析
我们需要分别计算每位同学需要多少糖果,如果 a[i] 大于前一位同学的糖果数量,则准备 a[i] 颗,否则需要比前一位同学 a[i-1] 多一颗
#include<bits/stdc++.h>using namespace std;int main() {
long long n, cnt = 0, a[1005]; cin >> n; a[0] = 0; // 方便第一位同学a[1]比较 for (int i = 1; i <= n; i++) { cin >> a[i]; if (a[i] <= a[i-1]) a[i] = a[i-1] + 1; cnt += a[i]; } cout << cnt;
return 0;}
202503-1 2025
题目描述
小 A 有一个整数 ,他想找到最小的正整数 使得下式成立:
其中 表示二进制按位与运算, 表示二进制按位或运算。如果不存在满足条件的 ,则输出 。
输入格式
一行,一个整数 。
输出格式
一行,一个整数,若满足条件的 存在则输出 ,否则输出 。
样例输入 1
1025
样例输出 1
1000
提示
对于所有测试点,保证 。
其中:
- 表示按位与运算,运算符为 。
- 表示按位或运算,运算符为 。
代码解析
枚举法,从 1 开始枚举,找到符合条件的 i 直接结束主函数,若循环结束也没有找到则输出 -1
#include<bits/stdc++.h>using namespace std;int main() {
int x; cin >> x; for (int i = 1; i <= 2025; i++) if ((x & i) + (x | i) == 2025) { cout << i; return 0; } cout << -1;
return 0;}
202503-2 词频统计
题目描述
在文本处理中,统计单词出现的频率是一个常见的任务。现在,给定 个单词,你需要找出其中出现次数最多的单词。在本题中,忽略单词中字母的大小写(即 Apple
、apple
、APPLE
、aPPle
等均视为同一个单词)。
请你编写一个程序,输入 个单词,输出其中出现次数最多的单词。
输入格式
第一行,一个整数 ,表示单词的个数;
接下来 行,每行包含一个单词,单词由大小写英文字母组成。
输入保证,出现次数最多的单词只会有一个。
输出格式
输出一行,包含出现次数最多的单词(输出单词为小写形式)。
样例输入 1
6ApplebananaappleOrangebananaapple
样例输出 1
apple
提示
对于所有测试点,,每个单词的长度不超过 ,且仅由大小写字母组成。
代码解析
GESP 三级考点只有字符串以及数组,解这道题稍微麻烦一些。
解法 1:
在
words
数组中保存新的单词,在数组a
中保存对应的单词出现的次数。
#include<bits/stdc++.h>using namespace std;int main() {
string words[105]; int a[105] = {0}, n, cnt = 0; cin >> n; while (n--) { string s; cin >> s; for (int i = 0; i < s.size(); i++) if ('A' <= s[i] && s[i] <= 'Z') s[i] += 'a'-'A'; int i = 0; for (i = 0; i <= cnt; i++) { // 若在数组中找到了单词,则对应的次数 a[i] 加一 if (words[i] == s) { a[i]++; break; } } // 若上面的 for 循环正常结束,则说明单词第一次出现,做好记录,cnt是单词数 if (i > cnt) { words[cnt] = s; a[cnt]++; cnt++; } } int max = 0; for (int i = 1; i < cnt; i++) if (a[i] > a[max]) max = i; cout << words[max];
return 0;}
解法 2:
直接使用
words
字符串记录出现过的单词,每次使用find()
在words
中找是否记录过单词,words
中单词s
首字母的位置可以直接作为桶标记的下标。例:
words:
"apple banana orange"
a:
{2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0 ..... }
表示 2 个apple
,1 个banana
,3 个orange
#include<bits/stdc++.h>using namespace std;int main() {
string words; int n, a[3005] = {0}; cin >> n; while (n--) { string s; cin >> s; for (int i = 0; i < s.size(); i++) if ('A' <= s[i] && s[i] <= 'Z') s[i] += 'a'-'A'; if (words.find(s) == -1) // 若单词不在 words 中,则拼接,加空格方便最后的输出 words += s + ' '; else a[words.find(s)]++; } int max = 0; for (int i = 1; i < 3005; i++) if (a[i] > a[max]) max = i; // 输出的时候以空格来区分 for (int i = max; words[i]!=' '; i++) cout << words[i];
return 0;}