【codechef】Coffee Breaks(dp,剪枝)

像所有其他程序员一样,Sergey 非常喜欢喝咖啡,于是他每天喝恰好 K 杯咖啡。
Sergey 的一天被分成 N 段。对于每段时间,他知道自己可以写多少 KB 代码。
对于每段时间,Sergey 可以选择是否喝一杯咖啡。如果他在某段时间喝了一杯咖啡,则
他在该段时间不写任何代码,但他可以获得状态加成——如果他在某段时间选择不喝咖啡,
而上一次喝咖啡的时间距离现在不超过 D 段,则在该段时间内他可以写出正常情况下 M 倍
的代码。
作为他的生产力顾问(你的新职位!),请帮助 Sergey 规划他一天喝咖啡的时间,使他在
喝了恰好 K 杯咖啡的前提下写出最多的代码。


输入格式
输入数据第一行包含一个整数 T ,表示数据组数。接下来是 T 组数据。
每组数据第一行包含四个整数 N; K; D 和 M 。
接下来的一行包含 N 个整数 A1; A
2; : : : ; A
N ,表示 Sergey 每段时间写代码的 KB 数。

输出格式
对于每组数据,输出 Sergey 在喝了恰好 K 杯咖啡的前提下写出最多的代码的 KB 数。
数据范围
• 1  M; Ai  1000


样例数据
输入
1
5 2 2 10
1 2 3 4 5

输出
110


样例解释
第一组样例,Sergey 在第 1 段和第 3 段喝咖啡。在这两段时间里他不写任何代码,但在
其余的时间里他的写的代码量将乘 10,故总的代码量为 (2 + 4 + 5)  10 = 110KB。

https://www.codechef.com/LTIME28/problems/COFFEE

#include <bits/stdc++.h>
#define pb push_back
#define sqr(x) (x)*(x)
#define sz(a) int(a.size())
#define reset(a,b) memset(a,b,sizeof(a))
#define oo 1000000007
 
using namespace std;
 
typedef pair<int,int> pii;
typedef long long ll;
 
const int maxn=5007;
 
int n,m,k,d,a[maxn];
ll dp[maxn][maxn],s[maxn];
int myq[maxn];
 
int main(){
//    freopen("input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d%d",&n,&k,&d,&m);
 
        for(int i=1; i<=n; ++i){
            scanf("%d",&a[i]);
            s[i]=s[i-1]+a[i];
            dp[0][i]=s[i];
        }
        for(int i=1; i<=k; ++i){
            int first=1, last=0;
            for(int p=i; p<=n; ++p){
                while(first<=last && p-myq[first]>d) ++first;
                while(first<=last && dp[i-1][myq[last]-1] - s[myq[last]]*m <= dp[i-1][p-1] - s[p]*m) --last;
                myq[++last]=p;
                dp[i][p] = (s[p] - s[myq[first]])*m + dp[i-1][myq[first]-1];
                if(p>i) dp[i][p] = max(dp[i][p], a[p] + dp[i][p-1]);
            }
        }
        printf("%lld\n",dp[k][n]);
    }
}


你可能感兴趣的:(【codechef】Coffee Breaks(dp,剪枝))