1 条题解
-
0
自动搬运
来自洛谷,原作者为

Alex_Wei
**搬运于
2025-08-24 22:23:59,当前版本为作者最后更新于2020-08-26 19:32:13,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
因为是简单题所以放一下官方题解吧。
题意简述:从给定序列 中选出一个子序列满足:对于所有不为最大值的 ,总有 使得 。求子序列所有数之和的最大值。
Subtask 1:。
傻子都会做的部分分。
Subtask 2:。
枚举 的所有子集并判断是否合法。可以预处理出所有合法对 满足 。时间复杂度为 。如果不预处理时间复杂度为 ,较难通过。
Subtask 4:。
枚举所有 使得 且 ,将所有这样的 之间连一条边,最后求出连通块里所有点的权值之和的最大值即可。时间复杂度 。
Subtask 3:。
类似 Subtask 4 枚举权值,时间复杂度 。
结论 1:
对于任意 满足 ,总有 或 。
证明 1:
不妨设 。当 时,原式不成立,所以 。
因为 ,,所以 。
又因为 且 是 的整数倍,所以 ,即 。
因为 ,所以 ,得到 。
带回原式得到 ,解得 或者 。
推论 1.1
根据结论 1,对于每个偶数 ,满足 且大于 的 有且只有一个,即 。而奇数则不存在这样的 。
根据上面的结论,我们很容易得出,如果将选出来的数从小到大排序,去重,一定满足 。
Subtask 7:无特殊限制。
因此, 枚举最小值就能确定整个序列 ,二分或用 map 实现在 的时间内查找一个数在序列 中的出现次数,并且记录一个数是否被计算过。
每个数最多只会被计算一次,总时间复杂度:二分 ,map ,不过 map 常数更大一点。
值得注意的是,如果不判断一个数是否被计算过,那么时间复杂度可能会退化成 ,只能通过 Subtask 5。
Subtask 6 是给不会二分或 map 的参赛者准备的部分分(不过可能没多大必要)。
代码如下。
#include <bits/stdc++.h> using namespace std; #define ll long long const int N=3e5+5; map <int,int> mp; int n,a[N]; ll ans; int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>a[i],mp[a[i]]++; sort(a+1,a+n+1); for(int i=1;i<=n;i++){ ll tmp=a[i],cnt=0; while(mp[tmp]){ cnt+=tmp*mp[tmp],mp[tmp]=0; if(tmp%2==0)tmp=tmp/2*3; else break; } ans=max(ans,cnt); } cout<<ans<<endl; return 0; }
- 1
信息
- ID
- 5796
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者