P9143 [THUPC 2023 初赛] 众数

题目描述

你有若干个[1,n] 内的正整数:对于 1≤i≤n,你有 ai​ 个整数 i。设S=∑i=1n​ai​。

对于一个序列 p1​,p2​,⋯,pl​,定义其众数 maj(p1​,p2​,⋯,pl​) 为出现次数最多的数。若有多个数出现次数最多,则其中最大的数为其众数。

现在你需要把这 S 个数排成一个序列 b1​,b2​,⋯,bS​,使得∑i=1S​maj(b1​,b2​,⋯,bi​) 最大。输出该最大值。

输入格式

第一行一个整数 n,表示值域。

接下来一行 n 个正整数 a1​,a2​,⋯,an​,表示每种数的个数。

输出格式

输出一行一个正整数表示 ∑i=1S​maj(b1​,b2​,⋯,bi​) 的最大值。

输入输出样例

输入 #1

3
1 3 2

输出 #1

17

考虑最终序列的形式。一个自然的想法是不断从  n摆到 1,如果没有这个数就跳过。

正确性证明:考虑众数序列 m1​∼mS​,根据众数定义,其中只能有不超过 ∑i=1n​min(ai​,an​) 个 n,只能有不超过∑i=1n​min(ai​,max(an−1​,an​)) 个n−1 或 n。以此类推,只能有不超过 ∑i=1n​min(ai​,maxj=pn​aj​) 个不小于 p 的数。而不断从 n 摆到 1 的序列恰好达到了所有上界。□□

接下来考虑贡献。考虑一个数 i 被第 j 次放入序列,那么它对应的众数为最大的 �p 使得 ap​≥j。因此,设 fj​ 表示最大的 p 使得 ap​≥j,则 ai​ 的贡献为 ∑j=1ai​​fj​。前缀和即可。

时间复杂度 O(n+a)。

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 5;
long long n, ans, a[N], f[N];
int main() {
  cin >> n;
  for(int i = 1; i <= n; i++) cin >> a[i];
  for(int i = n, mx = 0; i; i--) {
    while(mx < a[i]) mx++, f[mx] = f[mx - 1] + i;
    ans += f[a[i]];
  }
  cout << ans << "\n";
  return 0;
}

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值