2025级新生第二轮周赛
7-1 明明的随机数
题目理解
输入:生成 N 个范围在 1 到 1000 之间的随机整数(N≤100),其中可能存在重复的数字。
处理逻辑:
去重:对于重复的数字,只保留一个,去除其余相同的数。
排序:将去重后的数字按从小到大的顺序排列。
输出:
第一行输出 M(去重后不同数字的个数)。
第二行输出 M 个从小到大排序后的不同数字。
简单来说,就是对一组可能包含重复的整数,先去除重复项,再对剩余的不同数字进行升序排序,最后输出结果的数量和具体数值。
#include<bits/stdc++.h>
using namespace std;
int main(){
set<int> s; // 定义set容器,自动去重且元素按升序排列
int n;
cin >> n; // 读取输入的整数个数n
for(int i = 0;i < n;i++){
int x;
cin >> x; // 读取每个整数
s.insert(x); // 插入set,自动去重(重复元素不会被插入)
}
cout << s.size() << '\n'; // 输出去重后的元素个数
// 按升序输出所有元素,确保元素间用空格分隔,最后无多余空格
int f = 0; // 标记是否为第一个元素
for(auto it:s){ // 遍历set中的元素(已自动排序)
if(!f) { // 第一个元素直接输出,不加分隔符
cout << it;
f = 1; // 标记已输出第一个元素
}
else { // 非第一个元素,先输出空格再输出元素
cout << " " << it;
}
}
}
7-2 考试座位号
题目理解
输入:
首先输入考生数量 N(≤1000),然后输入 N 行考生信息,每行包含 “准考证号(16 位数字) 试机座位号 考试座位号”。
接着输入查询次数 M(≤N),再输入 M 个待查询的试机座位号。
处理逻辑:需要建立 “试机座位号” 到 “准考证号” 和 “考试座位号” 的映射关系,以便快速响应查询。
输出:对于每个待查询的试机座位号,输出对应的考生准考证号和考试座位号,两者用一个空格分隔。
简单来说,就是要实现一个基于 “试机座位号” 的信息检索系统,快速匹配并输出考生的准考证号和考试座位号。
#include<bits/stdc++.h>
using namespace std;
// 用两个数组分别存储:
// x[b] = 试机座位号为b的考生的准考证号
string x[1004];
// y[b] = 试机座位号为b的考生的考试座位号
int y[1004];
int main(){
int n;
cin >> n; // 读取考生总人数n
// 循环读入每个考生的信息
for(int i = 0;i < n;i++){
string a; // 准考证号
int b,c; // b=试机座位号,c=考试座位号
cin >> a >> b >> c;
// 用试机座位号b作为下标,存储对应的准考证号和考试座位号
x[b] = a;
y[b] = c;
// 注释掉的结构体用法,与数组用法功能一致
// x[b].zkz = a,x[b].ks = c;
}
int m;
cin >> m; // 读取查询次数m
// 循环处理每个查询
for(int i = 0;i < m;i++){
int a; // 待查询的试机座位号
cin >> a;
// 直接通过试机座位号a作为下标,输出对应的准考证号和考试座位号
cout << x[a] << ' ' << y[a] << '\n';
// 注释掉的结构体输出方式
// cout << x[a].zkz << ' ' << x[a].ks << '\n';
}
}
7-3 帅到没朋友
题目理解
输入:
首先给出朋友圈的个数 N(≤100);
然后 N 行,每行先给出一个朋友圈的人数 K(≤1000),接着列出该朋友圈内所有人的 5 位 ID(从 00000 到 99999);
再给出待查询的人数 M(≤10000),随后一行列出 M 个待查询的 ID。 判断规则:“帅到没朋友的人” 有两种情况:
根本没出现在任何朋友圈里;
出现在某个朋友圈里,但该朋友圈只有自己一个人(即 K=1)。
输出:按查询顺序输出所有 “帅到没朋友的人” 的 ID,ID 间用一个空格分隔,行首尾无多余空格;如果没有人符合条件,输出 No one is handsome。
简单来说,就是要从查询的 ID 中,筛选出那些 “不在任何朋友圈” 或 “仅在只有自己的朋友圈” 的人,并按查询顺序去重后输出。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n; // 读取朋友圈的个数n
// 哈希表p用于标记"有朋友的人":键为ID,值为1表示该ID有朋友
unordered_map<string,int> p;
// 遍历每个朋友圈
for(int i = 0;i < n;i++){
int k;
cin >> k; // 读取当前朋友圈的人数k
for(int j = 0;j < k;j++){
string b;
cin >> b; // 读取朋友圈中每个人的ID
// 只有当朋友圈人数>1时,才标记该ID"有朋友"(排除k=1的情况)
if(k != 1) p[b] = 1;
}
}
int m;
cin >> m; // 读取待查询的人数m
int f = 0; // 标记是否已有输出(用于控制空格)
// 遍历每个待查询的ID
for(int i = 0;i < m;i++){
string b;
cin >> b; // 读取查询的ID
// 若该ID不在p中(即"没朋友")
if(p.count(b) == 0) {
// 第一次输出直接打印ID,后续输出前加空格
if(!f) {
f = 1;
cout << b;
} else {
cout << ' ' << b;
}
// 标记该ID已输出(避免重复输出同一个ID)
p[b] = 2;
}
}
// 若没有符合条件的ID,输出提示信息
if(!f){
cout << "No one is handsome" << '\n';
}
}
7-4 到底有多二
题目理解
基础定义:“犯二程度” 是数字中包含2的个数与其位数的比值。 额外倍数:
如果数字是负数,程度增加0.5倍(即乘以1.5);
如果数字是偶数,程度再增加1倍(即乘以2)。
输入输出: 输入一个不超过 50 位的整数N;
输出N的犯二程度,结果保留小数点后两位(以百分比形式呈现)。
简单来说,就是先统计数字中2的个数和总位数,再结合 “负数”“偶数” 两个条件计算倍数,最终得到犯二程度的百分比。
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin >> s; // 读取输入的整数(以字符串形式处理,支持大数字)
float a = 0; // 统计数字中'2'的出现次数
int l = s.size(); // 记录字符串长度(包含符号位)
// 遍历字符串,统计'2'的个数
for(int i = 0;i < l;i++){
if(s[i] == '2') a=a+1;
}
float bs = 1; // 倍数因子,初始为1
// 如果是负数(首位为'-'),倍数乘以1.5,且有效数字位数减1(排除符号位)
if(s[0] == '-') bs*=1.5,l--;
// 如果是偶数(最后一位数字为偶数),倍数再乘以2
if((s[s.size()-1]-'0')%2 == 0) bs*=2.0;
// 计算犯二程度:(2的个数 / 有效位数) * 倍数 * 100%
float ans = a/(l*1.0);
printf("%.2f",ans*bs*100); // 保留两位小数输出百分比数值
cout << '%'; // 输出百分号
}
7-5 谁先倒
题目理解
划拳规则:两人各自喊一个数字、划一个数字。若某人划出的数字等于两人喊出数字之和,则该人输,需喝一杯酒。两人同赢或同输则继续,直到出现唯一输家。
输入:
第一行是甲、乙的酒量(最多能喝的杯数,非负整数)。
第二行是划拳轮数N,随后N行是每轮划拳记录,格式为 “甲喊 甲划 乙喊 乙划”。
输出:
第一行输出先倒下的人(A代表甲,B代表乙)。
第二行输出未倒下的人喝的杯数。
一旦有人酒量耗尽(喝的杯数超过其酒量),程序终止,后续数据无需处理。
简单来说,就是模拟划拳过程,统计两人的喝酒杯数,判断谁先超出酒量,从而确定先倒下的人及另一人的喝酒数。
#include<bits/stdc++.h>
using namespace std;
int main(){
int a1,a2;
cin >> a1 >> a2; // 输入甲、乙的酒量(最多能喝的杯数)
int ans1 = 0,ans2 = 0; // 记录甲、乙当前喝的杯数
int n;
cin >> n; // 输入划拳轮数
for(int i = 0;i < n;i++){
// 读取本轮数据:甲喊x2、甲划x1;乙喊y2、乙划y1
int x1,x2,y1,y2;
cin >> x2 >> x1 >> y2 >> y1;
// f1标记甲是否输(1表示输,0表示赢),f2标记乙是否输
int f1 = 0,f2 = 0;
// 若甲划的数等于两人喊的数之和,甲输
if(x1 == x2 + y2){
f1 = 1;
}
// 若乙划的数等于两人喊的数之和,乙输
if(y1 == x2 + y2){
f2 = 1;
}
// 只有一人输时,对应人喝酒杯数+1
if(f1 && !f2){ // 甲输乙赢,甲喝酒
ans1++;
}
if(!f1 && f2){ // 乙输甲赢,乙喝酒
ans2++;
}
// 若有人喝的杯数超过酒量(达到酒量+1),终止循环
if(ans1 == a1 + 1 || ans2 == a2 + 1){
break;
}
}
// 输出结果:先倒下的人及另一人喝的杯数
if(ans1 == a1 + 1){ // 甲先倒下
cout << 'A' << '\n' << ans2;
} else if(ans2 == a2 + 1){ // 乙先倒下
cout << 'B' << '\n' << ans1;
}
}
7-6 Legs
题目理解
场景:农场里只有鸡(2 条腿)和牛(4 条腿),已知总腿数 n,要求计算最少的动物总数。
思路:要使动物总数最少,应尽可能多的养腿数多的动物(即牛)。因此,先尽可能多的计算牛的数量,剩余的腿数用鸡来补充。
输入输出:
输入:测试用例数 t,每个测试用例给出总腿数 n(n 是偶数)。
输出:每个测试用例对应的最少动物总数。
简单来说,就是通过 “优先养牛,剩余腿数养鸡” 的策略,计算满足总腿数 n 的最少动物数量。
#include<bits/stdc++.h>
using namespace std;
int main(){
int T;
cin >> T; // 读取测试用例数量T
while(T--){ // 循环处理每个测试用例
int n;
cin >> n; // 读取总腿数n(题目保证n是偶数)
// 计算最少动物总数:
// 1. n/4:尽可能多的牛(每头牛4条腿)的数量
// 2. (n%4>0):若剩余腿数>0(只能是2条,因n是偶数),需加1只鸡
cout << n/4 + (n%4 > 0) << '\n';
}
}
7-7 Beautiful Year
题目注释
输入:一个年份 y(范围是 1000 ≤ y ≤ 9000)。
输出:严格大于 y 的最小的、所有数字互不重复的年份。
例如,给定 y=1987,下一个满足条件的年份是 2013(因为 1988 及之后的年份存在重复数字,直到 2013 所有数字才互不相同)。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n; // 读取输入的年份n
// 从n+1开始逐个检查年份,直到找到符合条件的年份
for(int i = n+1;;i++){
map<int,int> p; // 用map存储年份中出现的数字(自动去重)
int t = i; // 临时变量t用于分解年份的每一位数字
// 分解年份的每一位数字,存入map
while(t){
p[t%10] = 1; // 取t的最后一位数字,存入map(键为数字,值无实际意义)
t /= 10; // 移除t的最后一位数字
}
// 若map的大小为4,说明年份的4个数字互不重复
if(p.size() == 4) {
cout << i << '\n'; // 输出该年份
break; // 找到后退出循环
}
}
}
7-8 Primary Task
题目理解
关键规则:“重要整数” 原本是10^x (比如 10^5是 100000),但被误写成了将指数直接拼接在 “10” 后的形式(比如10^5误写成 105,10^19误写成 1019)。
输出:对于每个a,如果它可以是某个10^x(x≥2)的误写形式,输出 “YES”,否则输出 “NO”。
简单来说,就是要检查每个输入的整数是否能拆分为 “10” + “一个不小于 2 的整数” 的形式,且原形式 10^x是合法的(即x≥2)。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n; // 读取测试用例数量n
for(int i = 0;i < n;i++){
string s;
cin >> s; // 读取待判断的整数(以字符串形式处理,方便拆分)
// 若数字长度小于3,不可能拆成"10"+"x"(x≥2),直接输出NO
if(s.size() < 3) {
cout << "NO" << '\n';
continue;
}
int f = 0; // 标记前两位是否为"10"
// 检查前两位数字是否组成10(s[0]是第一位,s[1]是第二位)
if((s[0]-'0')*10 + (s[1]-'0') == 10) {
f = 1; // 前两位是10,标记为1
}
// 若前两位是10,且第三位及以后组成的数字≥2(排除"101"这种x=1的情况)
if(f && (s[2] >= '1' && s != "101")) {
cout << "YES" << '\n';
} else {
cout << "NO" << '\n';
}
}
}
7-9 找筷子
题目理解
场景:一堆筷子中,只有一只筷子是落单的(出现一次),其余筷子都成双(出现两次)。
输入:
第一行是筷子的数量 n(n 为奇数)。
第二行是 n 个整数,表示每根筷子的长度 a[i]。
输出:落单筷子的长度。
简单来说,就是要从一组数中,找出唯一出现一次的那个数(其余数都出现两次)。
#include<bits/stdc++.h>
using namespace std;
signed main(){
ios::sync_with_stdio(0); // 关闭输入输出同步,加速读写
cin.tie(0),cout.tie(0); // 解除cin与cout的绑定,进一步加速
int n;
cin >> n; // 读取筷子的数量n(n为奇数)
int sum = 0; // 用于存储异或运算的结果
// 遍历每根筷子的长度
for(int i = 0;i < n;i++){
int x;
cin >> x; // 读取当前筷子的长度
sum ^= x; // 关键:用异或运算累计结果
}
// 最终sum即为落单筷子的长度
cout << sum << '\n';
}
7-10 篮子里的甜甜圈
题目理解
场景:篮子里有甜甜圈,店主会进行 “放入”(操作 1)、“取出”(操作 2)甜甜圈的操作;流浪汉会在操作 3 时拿走当前篮子里质量最大的甜甜圈。
输入:
第一行是初始甜甜圈数量 n 和操作数量 q(均≤2×10⁵)。
第二行是 n 个初始甜甜圈的质量 w[i](≤10⁹)。
接下来 q 行是操作:
操作 1:放入一个质量为 w 的甜甜圈;
操作 2:取出一个质量为 w 的甜甜圈(保证该甜甜圈存在);
操作 3:流浪汉拿走当前最大质量的甜甜圈,需输出该质量,并累计总偷取质量。
输出:
每次操作 3 时输出流浪汉拿走的甜甜圈质量;
所有操作结束后输出流浪汉总共偷取的质量。
简单来说,就是要维护一个 “动态的最大质量集合”,支持快速的 “插入”“删除”“取最大值” 操作,并统计取最大值的总质量。
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); // 关闭输入输出同步,加速读写
cin.tie(nullptr); // 解除cin与cout绑定,进一步优化速度
int n, q;
cin >> n >> q; // 读取初始甜甜圈数量n和操作数量q
priority_queue<int> pq; // 大根堆,用于快速获取当前最大质量的甜甜圈
unordered_map<int, int> cnt; // 哈希表,记录每种质量的甜甜圈实际数量(解决堆中冗余元素问题)
// 初始化:加入初始甜甜圈
for (int i = 0; i < n; ++i) {
int w;
cin >> w;
pq.push(w); // 放入堆中
cnt[w]++; // 计数+1
}
long long sum = 0; // 记录流浪汉偷取的总质量
// 处理每一个操作
while (q--) {
int op;
cin >> op;
if (op == 1) { // 操作1:放入一个质量为w的甜甜圈
int w;
cin >> w;
pq.push(w); // 加入堆
cnt[w]++; // 计数+1
}
else if (op == 2) { // 操作2:取出一个质量为w的甜甜圈
int w;
cin >> w;
cnt[w]--; // 计数-1(不直接操作堆,避免堆结构破坏)
}
else if (op == 3) { // 操作3:流浪汉拿走当前最大质量的甜甜圈
// 清除堆中"已被取完"的冗余元素(计数为0的质量)
while (!pq.empty() && cnt[pq.top()] == 0) {
pq.pop();
}
// 取出当前最大质量的甜甜圈
if (!pq.empty()) {
int ma = pq.top(); // 获取最大值
pq.pop(); // 从堆中移除
cnt[ma]--; // 计数-1
sum += ma; // 累加偷取总质量
cout << ma << '\n'; // 输出本次偷取的质量
}
}
}
cout << sum << '\n'; // 输出偷取的总质量
return 0;
}
7-11 互评成绩
题目理解
评分规则:每个学生的作业会被 k 个同学评审,得到 k 个成绩。需要去掉一个最高分和一个最低分,将剩余分数取平均,作为该学生的最终成绩。
输入: 第一行给出三个正整数 N(学生总数,3 < N ≤ 10⁴)、k(每份作业的评审数,3 ≤ k ≤ 10)、M(需要输出的学生数,≤20)。
随后 N 行,每行给出 k 个评审成绩(范围 [0, 100])。
输出:
按非递减顺序输出最后得分最高的 M 个成绩,保留小数点后 3 位,分数间用一个空格分隔,行首尾无多余空格。
简单来说,就是对每个学生的 k 个成绩进行 “去最高、去最低、求平均” 的计算,然后将所有学生的最终成绩排序,输出前 M 个最高的成绩。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k,m;
cin >> n >> k >> m; // 读取学生总数n、每份作业的评审数k、需输出的学生数m
float a[n+1]; // 存储每个学生的最终成绩
// 计算每个学生的最终成绩
for(int i = 0;i < n;i++){
deque<int> d; // 用双端队列存储当前学生的k个评审成绩
for(int j = 0;j < k;j++){
int x;
cin >> x; // 读取一个评审成绩
d.push_back(x); // 加入队列
}
sort(d.begin(),d.end()); // 对成绩排序(从小到大)
d.pop_back(); // 去掉最高分(队尾元素)
d.pop_front(); // 去掉最低分(队头元素)
// 计算剩余k-2个成绩的总和
int sum = 0;
for(int j = 0;j < k-2;j++){
sum += d[j];
}
// 计算平均分作为最终成绩(转换为浮点数除法)
a[i] = sum / ((k-2)*1.0);
}
sort(a,a+n); // 对所有学生的最终成绩从小到大排序
// 输出得分最高的m个成绩(即排序后的最后m个元素)
int f = 0; // 标记是否为第一个输出,控制空格
for(int i = n-m;i < n;i++){
if(!f){ // 第一个元素直接输出,不加分隔符
f = 1;
printf("%.3f",a[i]); // 保留3位小数
} else { // 后续元素前加空格
cout << ' ';
printf("%.3f",a[i]);
}
}
}
7-12 彩虹瓶
题目理解
装填规则:需要按顺序(1 到 N)装填颜色。工人从工厂按发货顺序搬箱子,若当前箱子是待装填的颜色则直接装填;否则堆到临时货架上。装填完一种颜色后,检查货架顶端是否是下一个待装填颜色,若是则取下装填,否则继续从工厂搬箱。同时货架容量有限,若堆积超过容量则无法完成。
输入:
第一行给出三个正整数 N(颜色数量,1 < N ≤ 10³)、M(临时货架容量,M < N)、K(发货顺序数量)。
随后 K 行,每行是 1 到 N 的一个排列,表示工厂的发货顺序。
输出:
对每个发货顺序,判断工人是否能顺利完成装填,能则输出 “YES”,否则输出 “NO”。
简单来说,就是模拟装填过程,检查是否能按顺序 1 到 N 完成装填,且货架堆积量不超过容量M。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, m, k;
cin >> n >> m >> k; // 输入颜色总数n、货架容量m、发货顺序数量k
// 遍历每个发货顺序
for(int i = 0; i < k; i++){
int a[n+1]; // 存储当前发货顺序的颜色序列
for(int j = 0; j < n; j++){
cin >> a[j]; // 读取该发货顺序的每个颜色
}
stack<int> s; // 用栈模拟临时货架
int cnt = 1; // 当前需要装填的目标颜色(从1开始,按顺序递增)
// 按发货顺序处理每个颜色箱子
for(int j = 0; j < n; j++){
s.push(a[j]); // 将当前箱子堆到货架上
// 检查货架顶端是否是当前需要的颜色,若是则持续装填
while(!s.empty() && s.top() == cnt){
cnt++; // 目标颜色更新为下一个
s.pop(); // 从货架取下并装填
}
// 若货架堆积量超过容量m,提前终止处理(无法完成)
if(s.size() > m) break;
}
// 判断是否成功完成:货架为空且所有颜色(1~n)都已按顺序装填
if(s.empty() && cnt == n + 1){
cout << "YES" << '\n';
} else {
cout << "NO" << '\n';
}
}
}
查看15道真题和解析