[语言月赛 202407] speech 的题解
在解题之前提交题解的代码会导致封禁。
作者:
概述
本题要求找出魅力值最大的语言编号,其中一套语言的魅力值定义为其语法数量与该语言使用人数的乘积,若有多套语言的魅力值并列最大则输出编号最小者。核心解法是用桶数组统计每套语言的使用人数,再按编号从小到大扫描一次,仅在严格大于当前最大值时更新答案。
分析
核心观察
一套语言的魅力值只由两个量决定:它自身的语法数量 与使用它的居民人数
。而
并不需要额外存储整条居民序列,把每个居民使用的语言编号直接当作下标做桶计数,就能在遍历居民的过程中统计出全部
。
思路
记 为使用语言
的居民人数,则语言
的魅力值为
,答案为使
取到最大值的、编号最小的
。
统计 有暴力与桶计数两种做法。暴力做法对每套语言都完整扫描一遍居民序列,时间为
,在
时约为
次操作,虽然可以接受但并不必要。注意到第
个居民使用的语言编号
恰好就是要累加的下标,于是可以在读入
时直接令
自增
,居民序列遍历完毕时全部
也就统计完毕,这一步只需
时间。
得到 后,从
到
顺序枚举语言,用变量
记录已扫描过的魅力值最大值、变量
记录取到该值的编号。更新条件写成严格大于
:当
与当前最大值相等时不更新,编号较小的语言因此得以保留,恰好满足并列取最小编号的要求;若写成大于等于
,并列时会不断替换成编号更大的语言,答案就错了。桶计数与一次扫描合起来,总时间为
。
具体示例
以样例 为例,
、
,两套语言的语法数量分别为
、
,居民使用的语言编号依次为
。
桶计数得到 、
。语言
的魅力值为
,语言
的魅力值为
,二者并列最大;由于
,输出编号
。
作为对照,样例 只把
改为
,此时语言
的魅力值为
,严格大于语言
的
,输出变为
。可见答案的走向完全由“严格大于”这一更新条件驱动。
算法步骤
- 读入
n与m。 - 读入
个整数存入数组
a,其中表示语言
的语法数量。
- 依次读入
个居民使用的语言编号,每读入一个编号就把对应的桶
cnt加,读完后
即为语言
的使用人数。
- 令
best为,
bestValue为。
- 从
到
枚举语言编号
i,计算;若该值严格大于
bestValue,则用它更新bestValue,并令best等于i。 - 输出
best。
复杂度分析
- 时间:
。读入语法数量、统计居民语言、扫描全部语言各为一次线性遍历。
- 空间:
。只需要长度为
的数组
a与cnt,居民的语言编号可以边读边统计,无需存储。
实现注意事项
- 更新最大值必须使用严格大于;写成大于等于会在魅力值并列时留下编号较大的语言,与输出最小编号的要求相反。
bestValue初始化为。由于
、
,所有魅力值均非负,而
严格小于任何可能的魅力值,故第一次比较必然成功,编号
至少会被记录一次。
可以取
,此时该语言的魅力值为
,仍然要参与比较,不能提前跳过。
- 魅力值的上界为
,
int足以容纳,改用位整型相乘可彻底避免溢出隐患。
- 数据规模较小,使用
cin直接读入即可;若追求稳妥可关闭同步流再读入。
源代码
#include <iostream>
#include <vector>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(m + 1, 0), cnt(m + 1, 0);
for (int i = 1; i <= m; ++i) {
std::cin >> a[i];
}
for (int j = 0; j < n; ++j) {
int b;
std::cin >> b;
++cnt[b];
}
int best = 1;
long long bestValue = -1;
for (int i = 1; i <= m; ++i) {
long long value = 1LL * a[i] * cnt[i];
if (value > bestValue) {
bestValue = value;
best = i;
}
}
std::cout << best << '\n';
return 0;
}
import sys
def main():
data = sys.stdin.buffer.read().split()
n = int(data[0])
m = int(data[1])
a = [0] * (m + 1)
for i in range(1, m + 1):
a[i] = int(data[1 + i])
cnt = [0] * (m + 1)
for j in range(n):
b = int(data[2 + m + j])
cnt[b] += 1
best = 1
best_value = -1
for i in range(1, m + 1):
value = a[i] * cnt[i]
if value > best_value:
best_value = value
best = i
sys.stdout.write(str(best) + "\n")
main()
评论