[语言月赛 202411] K/D/A 的题解
在解题之前提交题解的代码会导致封禁。
作者:
概述
本题要求根据每名战士的三个参数 ,按题面给定的三档规则算出各自的实力,并输出实力最高者的编号(保证最高者唯一)。核心解法是按
与
、
的大小关系套用对应档位的公式逐名算分,再用打擂台的方式在线维护最大值及其下标。
分析
核心观察
每名战士的实力只由他自己的 决定,与其他人无关,因此可以边读入边算出实力,只需要记住“目前的最大值”和“取到它的编号”。三档公式的判定有先后顺序:先看
是否达到
,不满足时才去看
是否不小于
。
思路
设第 名战士的参数为
,题面给出的实力计算规则是一个分段函数:
三段按顺序判定。第二段是“否则,若 ”,它的完整前提是
且
;当
时必然有
,所以剩下的情况就是
,对应第三段。判定顺序不可交换:若先判
,那么
这类应当走第一档的数据会被错误地送进第二档。
三段的取值都不小于 :第一段中
且
,乘积与加数均非负;第二段中
保证
,乘
后也非负;第三段是
。由数据范围
可得实力的最大值出现在
处,为
实力最高的战士唯一,所以逐个比较时用严格大于即可,不必处理并列。
由于只需要最强者的编号,不必保存全部实力:读入一名战士就算出他的实力 ,与当前最大值比较,只在
严格更大时把它记为新的最大值并更新答案下标。朴素做法是先把
名战士的信息全部存下来,再扫一遍求最大值及其下标,时间同为
,但空间需要
;边读边算把空间降到了
。
具体示例
以样例 为例。第
名战士
,此时
但
,走第二档,实力为
第 名战士
,此时
,走第三档,实力为
。第
名战士
,此时
且
,走第二档,实力为
。三者中
最大,对应第
名战士,故输出
。
样例 的两名战士恰好落在
的分界线两侧:
的
,不满足
,走第二档得
;
的
,满足第一档得
。第一档的
更大,故输出
。两人的
只差
,却分属两个档位。若把判据误写成
,第
名战士就会被判入第二档,实力只有
,反而小于第
名的
,答案会错成
。可见分界处的等号必须取对。
样例 中两名战士的
都等于
,第二档的
都是
,实力分别为
与
,胜负完全由
决定:
在第二档里是加项而不是乘数。
算法步骤
- 读入战士人数
n。 - 令当前最大值
best为,答案下标
ans为。
- 对
i从到
n:读入第i名战士的k、d、a,按先后次序判断分档并算出实力v—— 若则
v为;否则若
则
v为;否则
v为。
- 若
v严格大于best,则把best更新为v,把ans更新为i。 - 输出
ans。
复杂度分析
- 时间:
,每名战士只做常数次比较与算术运算。
- 空间:
,只用到人数、当前最大值、答案下标以及当前战士的参数等常数个变量。
实现注意事项
- 每行形如
,把分隔符
直接写进格式串即可一次读入三个整数,例如
,不必先把整行读成字符串再手工切分。
- 三个分支的顺序不能颠倒:必须先判
,再判
,剩下的才是
。先判
会让
的数据走错档位。
- 分界处要取等号:
属于第一档,
属于第二档;
时
,属于第二档。
- 实力最小为
(如
时
),把当前最大值初始化为
可以保证第一个战士一定会触发更新。
- 比较必须用严格大于。虽然题目保证实力最高者唯一,但只要写法上不取等号,即使出现并列也会稳定地保留较小编号。
- 实力上界为
,未超出
位有符号整数的范围,标程仍统一用
long long存放实力并在乘法处做类型提升,留出余量。 - 输出只有一个整数,注意行末换行。
最大为
,使用
scanf与printf的读入写出方式足以应对,不需要额外的读入优化。
源代码
#include <cstdio>
int main() {
int n;
if (scanf("%d", &n) != 1) return 0;
long long best = -1;
int ans = 1;
for (int i = 1; i <= n; ++i) {
int k = 0, d = 0, a = 0;
if (scanf("%d/%d/%d", &k, &d, &a) != 3) return 0;
long long v;
if (k - d >= 10)
v = 1LL * k * (k - d) + a;
else if (k >= d)
v = 1LL * (k - d + 1) * 3 + a;
else
v = 1LL * a * 2;
if (v > best) {
best = v;
ans = i;
}
}
printf("%d\n", ans);
return 0;
}
import sys
def main():
data = sys.stdin.read().split()
n = int(data[0])
best = -1
ans = 1
for i in range(1, n + 1):
k, d, a = map(int, data[i].split('/'))
if k - d >= 10:
v = k * (k - d) + a
elif k >= d:
v = (k - d + 1) * 3 + a
else:
v = a * 2
if v > best:
best = v
ans = i
print(ans)
main()
评论