codeforces-1395D Boboniu Chats with Du【前缀和】【枚举】

题目

codeforces-1395D

题意

给出n个数的数组a,从1开始遍历数组
当a[i]<=m时,直接拿走a[i],
当a[i]>m时,拿走a[i],i后面的d个数不能拿,即a[i+1],a[i+2]…a[i+d]不能拿走;
重新排列数组,使得拿走的数总和最大

题解

先把>m和<=m的数分开来,最大的数肯定放在最后面(因为后面没有数了,不会对其他数造成影响),然后计算最多可以拿多少个>m的,即k = min(big_cnt,(n-1)/(d+1)),枚举取>m的数的数量,通过前缀和求总和,更新答案;
例如,>m的数取2个,d=2时;
取>m最大的3个数的和(包括放在数组最后一个的数),那么有2*2=4个数不能选,我们要先减>m的数中没取的,剩余的数再从<=m的数中最小的减去;

代码

/*
 * @author: arc
 * @date: 2020-08-13 23:11:13
 */
#include
#include
using namespace std;
typedef long long ll,LL;
const int maxn = 1e5+5;
 
ll a[maxn], big[maxn], little[maxn];
ll big_sum[maxn], little_sum[maxn];
 
bool cmp(ll a, ll b) { return a > b; }
 
int main(){
    int n, d;
    ll m;
    int big_cnt = 0;
    int little_cnt = 0;
    scanf("%d%d%lld", &n, &d, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        if (a[i] > m) {
            big[++big_cnt] = a[i];
        } else {
            little[++little_cnt] = a[i];
        }
    }
    sort(big + 1, big + 1 + big_cnt, cmp);
    sort(little + 1, little + 1 + little_cnt, cmp);
    big_sum[0] = 0;
    big_sum[1] = 0;
    for (int i = 1; i <= big_cnt; i++) {
        big_sum[i] = big_sum[i - 1] + big[i];
    }
    little_sum[0] = 0;
    for (int i = 1; i <= little_cnt; i++) {
        little_sum[i] = little_sum[i - 1] + little[i];
    }
 
    int k = (n - 1) / (d + 1);
    k = min(k, big_cnt);
    ll ans = 0;
    for (int i = 0; i <= k; i++) {
        int big_remove = max(0, i * d - max(0, (big_cnt - 1 - i)));
        int pos = little_cnt - big_remove;
        int pos2 = min(big_cnt, i + 1);
        ans = max(ans, little_sum[pos] + big_sum[pos2]);
    }
    printf("%lld\n", ans);
    return 0;
}

你可能感兴趣的:(acm)