CF940E. Cashback [贪心+dp]

这是一道来自Codeforces的题目,要求找到数组分割成连续子数组后的最小价值总和,其中子数组价值为其元素之和减去最小w个数的和。文章介绍了贪心策略和动态规划的解题思路,提供了最优分割方法的解释和转移方程的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E Cashback
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Since you are the best Wraith King, Nizhniy Magazin «Mir» at the centre of Vinnytsia is offering you a discount.

You are given an array a of length n and an integer c.

The value of some array b of length k is the sum of its elements except for the smallest. For example, the value of the array [3, 1, 6, 5, 2] with c = 2 is 3 + 6 + 5 = 14.

Among all possible partitions of a into contiguous subarrays output the smallest possible sum of the values of these subarrays.

Input
The first line contains integers n and c (1 ≤ n, c ≤ 100 000).

The second line contains n integers ai (1 ≤ ai ≤ 109) — elements of a.

Output
Output a single integer — the smallest possible sum of values of these subarrays of some partition of a.

Examples
inputCopy
3 5
1 2 3
outputCopy
6
inputCopy
12 10
1 1 10 10 10 10 10 10 9 10 10 10
outputCopy
92
inputCopy
7 2
2 3 6 4 5 7 1
outputCopy
17
inputCopy
8 4
1 3 4 5 5 3 4 1
outputCopy
23
Note
In the first example any partition yields 6 as the sum.

In the second example one of the optimal partitions is [1, 1], [10, 10, 10, 10, 10, 10, 9, 10, 10, 10] with the values 2 and 90 respectively.

In the third example one of the optimal partitions is [2, 3], [6, 4, 5, 7], [1] with the values 3, 13 and 1 respectively.

In the fourth example one of the optimal partitions is [1], [3, 4, 5, 5, 3, 4], [1] with the values 1, 21 and 1 respectively.

题意:给一个有n个元素的序列,可以任意分割成若干个序列,每个序列的价值=元素总和-序列内最小的w个数的和(其中w是序列长度/c下取整),给出n和原序列以及c的值,求总价值的最小值

题解:总价值的最小值就相当于让减去的数字之和尽可能大,而显然将序列分解成若干个长度为c的序列之和能去掉的最小值之和最大,因为两个长度为c的序列的两个最小值之和一定不小于一个长度为2c的序列的最小值+次小值。接下来很容易用当前元素i是否和前c-1个元素结合成一个序列写转移方程

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=1e5+5;
ll a[maxn],dp[maxn],sum[maxn];
int main(){
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}
    multiset<ll>st;
    for(int i=1;i<=n;i++)dp[i]=1e16;
    for(int i=1;i<=n;i++){
        st.insert(a[i]);
        dp[i]=min(dp[i],dp[i-1]+a[i]);
        if(i>=c){
            dp[i]=min(dp[i],dp[i-c]+sum[i]-sum[i-c]-*(st.begin()));
            st.erase(st.find(a[i-c+1]));
        }
    }
    printf("%lld\n",dp[n]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值