题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2395
要换灯泡的话,一定是这个种类的全换,将灯泡按电压排序,如果有灯的种类要替换成灯 (i),那么灯 (i) 的 (c[i]*l[i]+k[i]) 一定是这段区间中最小的,最终替换成的所有灯泡的 (c[i]*l[i]+k[i]) 一定是递增的,如下图
红线是灯泡原来的值,黑框是替换以后的值的样子
所以我们就可以考虑 (dp),令 (dp[i]) 表示前 (i) 个灯泡的答案,转移是考虑从哪一段开始将这些灯泡都替换成灯泡 (i)
[dp[i] = max{dp[j]+(s[j]-s[i])*c[i]+k[i]}(0<=j<i)
]
其中 (s[i]) 表示前 (i) 个灯泡的总数量
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1010;
int n;
int s[maxn], dp[maxn];
struct Lamp{
int v, k, c, l;
bool operator < (const Lamp &x) const{
return v < x.v;
}
}a[maxn];
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
while(scanf("%d", &n) == 1 && n){
for(int i = 1 ; i <= n ; ++i){
scanf("%d%d%d%d", &a[i].v, &a[i].k, &a[i].c, &a[i].l);
}
sort(a + 1, a + 1 + n);
s[0] = 0;
for(int i = 1 ; i <= n ; ++i) s[i] = s[i-1] + a[i].l;
memset(dp, 0x3f, sizeof(dp));
dp[0] = 0;
for(int i = 1 ; i <= n ; ++i){
for(int j = 0 ; j < i ; ++j){
dp[i] = min(dp[i], dp[j] + (s[i] - s[j]) * a[i].c + a[i].k);
}
}
printf("%d
", dp[n]);
}
return 0;
}