0
点赞
收藏
分享

微信扫一扫

D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)

原题链接: ​​https://codeforces.com/contest/1395/problem/D​​

题意: 你用过QQ吧,用过QQ就跳过咯?就是你有一堆有趣的快乐因子,然后你要搞怪群主,如果你的快乐因子大于群主的忍耐程度D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_前缀和,那么你将会被禁言D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_思维_02天,问你在有限的D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_暴力枚举_03天中,你能达到的最大快乐因子总和。

解题思路: 这道题有点水,没错,确实有点水,你不信?听我的思路慢慢道来。我们有一堆快乐因子,有的是小于等于D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_前缀和的,有的是大于等于D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_前缀和的。这两者一种会被禁言,一种不会被禁言,我们就把它们分成两组。再看我们的选择:我们可以选择什么?如果枚举完我们所有的选择情况,计算快乐因子总和,再取所有的情况最大值这道题就解决了。所以关键就是我们的选择有什么?
既然我们想要快乐因子总和最大,我们挑在不被禁言的组中肯定是挑快乐因子最大的,在被禁言的组中也肯定是挑快乐因子最大的。还有一个特殊的点就是我们在第D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_前缀和_06天的时候可以选择被禁言达成最优效益,因为那个时候群主奈何不了你了,所以那个时候我们是不会被禁言的所以我们设我们选择了D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_#define_07个快乐因子,那么会禁言D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_ios_08,又因为使用每个快乐因子占用一天。所以我们总共花去了D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_前缀和_09天,所以我们用剩余的天数去使用不被禁言的快乐因子即可。OK,这样思路就十分清晰了。
我们的任务有:

  1. 对快乐因子分组,并从大到小排序(我们要最大肯定是要选最大的。)并用一个数组统计未被禁言的前缀和,这个用于我们之后求出的剩余天数D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_暴力枚举_10直接用下标就可以得出结果。
  2. 确定会被禁言的快乐因子的上限和下限用于D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_思维_11循环。通过D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_#define_12循环来枚举所有情况,得到最大值D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_思维_13
  3. 值得注意的一点就是可能没有会被禁言的快乐因子,所以我们要让D. Boboniu Chats with Du(枚举+思维)Codeforces Round #664 (Div. 2)_思维_13的初值等于不被禁言的因子前缀最大和。

现在你不会觉得这题目难了吧,若还觉得难,看看代码吧,我贴了详细注释,加油。

AC代码:

/*
*
*
*/
#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;
}


举报

相关推荐

0 条评论