像所有其他程序员一样,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]);
}
}