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';
        }
    }
}
全部评论

相关推荐

1jian10:既然没有路过,那就直接投28k+,出门在外身份是自己给的
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务