D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)
原题链接: https://codeforces.com/contest/1395/problem/D
题意: 你用过QQ吧,用过QQ就跳过咯?就是你有一堆有趣的快乐因子,然后你要搞怪群主,如果你的快乐因子大于群主的忍耐程度 m m m,那么你将会被禁言 d d d天,问你在有限的 n n n天中,你能达到的最大快乐因子总和。
解题思路: 这道题有点水,没错,确实有点水,你不信?听我的思路慢慢道来。我们有一堆快乐因子,有的是小于等于
m
m
m的,有的是大于等于
m
m
m的。这两者一种会被禁言,一种不会被禁言,我们就把它们分成两组。再看我们的选择:我们可以选择什么?如果枚举完我们所有的选择情况,计算快乐因子总和,再取所有的情况最大值这道题就解决了。所以关键就是我们的选择有什么?
既然我们想要快乐因子总和最大,我们挑在不被禁言的组中肯定是挑快乐因子最大的,在被禁言的组中也肯定是挑快乐因子最大的。还有一个特殊的点就是我们在第
n
n
n天的时候可以选择被禁言达成最优效益,因为那个时候群主奈何不了你了,所以那个时候我们是不会被禁言的。所以我们设我们选择了
x
x
x个快乐因子,那么会禁言
(
x
−
1
)
∗
d
(x-1)*d
(x−1)∗d天,又因为使用每个快乐因子占用一天。所以我们总共花去了
(
x
−
1
)
∗
d
+
x
(x-1)*d+x
(x−1)∗d+x天,所以我们用剩余的天数去使用不被禁言的快乐因子即可。OK,这样思路就十分清晰了。
我们的任务有:
- 对快乐因子分组,并从大到小排序(我们要最大肯定是要选最大的。) 并用一个数组统计未被禁言的前缀和,这个用于我们之后求出的剩余天数 r e s res res直接用下标就可以得出结果。
- 确定会被禁言的快乐因子的上限和下限用于 f o r for for循环。通过 f o r for for循环来枚举所有情况,得到最大值 a n s ans ans。
- 值得注意的一点就是可能没有会被禁言的快乐因子,所以我们要让 a n s ans ans的初值等于不被禁言的因子前缀最大和。
现在你不会觉得这题目难了吧,若还觉得难,看看代码吧,我贴了详细注释,加油。
AC代码:
/*
*邮箱:unique_powerhouse@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h> //POJ不支持
#define rep(i,a,n) for (ll i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (ll i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5+5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//
//所有的数据最好都用long long。我交了一发没用ll数据溢出了。
ll n,m,d;//n为天数,d为禁言天数,m为界限值。
ll a[maxn],b[maxn],pre[maxn],cnt1,cnt2;//pre数组统计未被禁言的前缀和,用于剩余天数的最大解。cnt1和cnt2统计他天数。
bool cmp(ll x,ll y){
//自定义比较函数作为sort的函数对象,也可以使用greater<int>().
return x>y;
}
int main(){
//freopen("in.txt", "r", stdin);//提交的时候要注释掉
IOS;
while(cin>>n>>d>>m){
cnt1=cnt2=0;
ll temp;
rep(i,1,n){
cin>>temp;
if(temp<=m)a[++cnt1]=temp; //统计不被禁言的快乐因子。
else b[++cnt2]=temp; //统计被禁言的快乐因子。
}
sort(a+1,a+1+cnt1,cmp);
sort(b+1,b+1+cnt2,cmp);
ll sum=0,ans=0,res;//sum统计被禁言的快乐因子总和,ans保存最优解,res存储剩余天数。
pre[0]=0;
rep(i,1,cnt1){
pre[i]=pre[i-1]+a[i];//求前缀和。
}
rep(i,cnt1+1,n){
pre[i]=pre[i-1];//未被禁言的快乐因子已经用完了,后面的也自然是如此等于最大的前缀和。
}
ans=pre[n];//提前统计好没有使用一天禁言天数的,因为禁言天数的因子可能没有。
rep(j,1,cnt2){
//j表示选取的禁言因子。
//接下来开始暴力枚举最优解。
sum+=b[j];
res=n-((j-1)*(d+1)+1);
if(res<0)break;//如果剩余天数小于0和大于不被禁言的因子数天数。自然就是失败的。
ans=max(ans,sum+pre[res]);
}
cout<<ans<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!