题目链接:http://fastvj.rainng.com/contest/306591#problem/F
题目大意:
思路:我们先把所有的灯泡按电压排(升)序。
结论一:
结论1:每种灯泡要么不换,要么全换。
如果单拿两种灯泡,我们什么情况换?
(1) 灯泡2的灯泡价格比灯泡1低。
(2) 灯泡2的价格比灯泡1的价格高,但是把灯泡1全部换成灯泡2,
可以减少灯泡的电源钱,比换灯泡的价格花费高。那么就是(L[i])*(c[j]-c[i])< K[i]
结论2:现我们将输入按照电压等级从小到大排序后,j < i,如果 j 要换成 i,
则从 j 到 i-1 都要换成 i。因为j换i那么减少的费用为(L[i])*(c[i]-c[j]) + K[i]
如果 j 要换成 i,没有换成j到i之间的灯泡,那么说明c[j]是i到j中最小的。
那么j-i之间灯泡都满足(L[i])*(c[i]-c[j]) + K[i]>0说明他们换成i都可以使费用减少。
因为i-n的灯泡电压比i大,他们不能换成i,在这个区间里面应该重复这个过程。
//大佬思路:
如果结论2成立,那么意味着这个升序列中有几个“断层”,它们之间的弱势灯泡
要被替换为右侧大功率灯泡。
首先,第n个由于功率最大,肯定是最后一个断层。然后,此时假设断层 i 的上一个断层为 j,由于 j 和 i 之间的灯泡
都要换成 i,所以dp[i] = dp[j] + 灯泡数量*i的单价 + i的电压源价格。
该暴力的时候也得暴力一下,上一个断层 j 无法直接得出,可以遍历1~i-1看看
哪种方案最优得之。
d[i]为灯 泡1~i的最小开销
故给出状态转移方程dp[i] = min{ dp[j] + (s[i]-s[j])*C[i] + K[i] }。
因为每个灯泡要么不换,要么全换,所以s[i]是灯泡数量前缀和。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
struct node
{
int v, k, c, L;
bool operator<(node &a)
{
return v<a.v;
}
}a[1010];
LL dp[1010], s[1010];
int main()
{
int n;
while(scanf("%d",&n),n)
{
memset(s, 0, sizeof(s));
for(int i=1;i<=n;i++)
{
dp[i]=(1<<31)-1;
scanf("%d%d%d%d",&a[i].v,&a[i].k,&a[i].c,&a[i].L);
}
sort(a+1, a+1+n);
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+a[i].L;
}
dp[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i;j++)
{
dp[i]=min(dp[j]+(s[i]-s[j])*a[i].c+a[i].k, dp[i]);
}
}
printf("%lld\n",dp[n]);
}
}