谁拿了最多奖学金

GitHub跳转原题关系图返回列表

逐名学生按五条严格大于条件累加奖金,并用严格大于维护最大者以保证并列取先出现者,O(N) 模拟。

OJ: roj

题目 ID: 3540

难度:入门

标签:模拟入门

创建: 2026-10-02 06:17

更新: 2026-10-06 13:36

题目描述

期末考试后按五条互不排斥的奖学金规则发奖金。输入第一行是学生总数 N,接下来 N 行每行:姓名、期末平均成绩 avg、班级评议成绩 cls、是否干部(Y/N)、是否西部省份(Y/N)、论文数。输出:奖金总数最高的学生姓名(并列取输入中最先的)、该生奖金、全体学生的奖金总和。N ≤ 100。

思路

逐名学生按题面五条严格大于条件累加奖金,同时累加全体总和。扫描时用严格大于更新最大者,并列时自然保留先出现的学生。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 06:18
# update_at: 2026-10-02 06:18

import sys


def bonus(avg: int, cls: int, cadre: bool, western: bool, papers: int) -> int:
    """这份数据满足哪几项奖学金条件,返回奖金总数。"""
    # 每行一个家族:五项奖学金的条件与奖金,符合就累加
    return (
        (8000 if avg > 80 and papers >= 1 else 0)   # 院士奖学金
        + (4000 if avg > 85 and cls > 80 else 0)    # 五四奖学金
        + (2000 if avg > 90 else 0)                 # 成绩优秀奖
        + (1000 if avg > 85 and western else 0)     # 西部奖学金
        + (850 if cls > 80 and cadre else 0)        # 班级贡献奖
    )


def solve() -> None:
    """逐个学生统计奖金,在线维护「奖金最多且出现最早」的学生。"""
    tokens = iter(sys.stdin.buffer.read().split())
    n = int(next(tokens))

    best_bonus, best_name = -1, ""
    total = 0
    for _ in range(n):
        name = next(tokens).decode()
        avg, cls = int(next(tokens)), int(next(tokens))
        is_cadre = next(tokens) == b"Y"    # 是否学生干部
        is_western = next(tokens) == b"Y"  # 是否西部省份学生
        papers = int(next(tokens))
        b = bonus(avg, cls, is_cadre, is_western, papers)
        total += b
        # 严格大于:并列时保留先出现的那个
        if b > best_bonus:
            best_bonus, best_name = b, name

    print(best_name)
    print(best_bonus)
    print(total)


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-06 13:36
 * update_at: 2026-10-06 13:36
 */
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

char name[25];          // 当前学生姓名
ll n;                   // 学生总数
ll avg, cls, papers;    // 当前学生的三个数值属性
char cadre, western;    // 当前学生是否干部 / 是否西部省份
ll best_bonus = -1;     // 当前最大个人奖金
char best_name[25];     // 当前奖金最多学生的姓名
ll total = 0;           // 全体奖金总和

// 按题面五条规则计算单个学生的奖金总数
ll calc(ll a, ll c, char is_cadre, char is_western, ll p) {
    ll res = 0;
    if (a > 80 && p >= 1) res += 8000;          // 院士奖学金
    if (a > 85 && c > 80) res += 4000;          // 五四奖学金
    if (a > 90) res += 2000;                    // 成绩优秀奖
    if (a > 85 && is_western == 'Y') res += 1000; // 西部奖学金
    if (c > 80 && is_cadre == 'Y') res += 850;    // 班级贡献奖
    return res;
}

int main() {
    scanf("%lld", &n);
    for (ll i = 1; i <= n; i++) {
        scanf("%s %lld %lld %c %c %lld", name, &avg, &cls, &cadre, &western, &papers);
        ll bonus = calc(avg, cls, cadre, western, papers);
        total += bonus;
        // 严格大于才更新,保证并列时取最先出现的学生
        if (bonus > best_bonus) {
            best_bonus = bonus;
            strcpy(best_name, name);
        }
    }
    printf("%s\n%lld\n%lld\n", best_name, best_bonus, total);
    return 0;
}