逐名学生按五条严格大于条件累加奖金,并用严格大于维护最大者以保证并列取先出现者,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;
}