Gym-100812I Dragon Delivers(区间DP思想)2017寒假集训

题意:Gym的讲故事题面真难读,百度的大佬也不太肯说题意QAQ,还是看了样例解释才读懂,英语太弱了。

就是说给出三个数n,d,c。n代表的是有n个物品每个在ti时刻要发送出去,每发送一次花费d,如果不马上发送,每秒每个物品要花费c,可以多个物品一起发,求的是最小的花费

数据范围:n <= 1000 其余为1e9

思路:设dp[i]为发送前i个物品的最小花费,显然每次转移对于每个物品都不知道它是绑起来等待发还是单独马上发。

但是根据状态的定义我们可以得知dp[i] = min(dp[j]+cost) 表示前1到j以最优方案发送,j+1到i捆绑到i出现时再发送。类似于区间dp,枚举断点j来更新dp[i]

另一个问题是cost如何计算呢?cost代表的是第j+1,j+2......i-1个物品的等待时间,第x个物品的花费是c*(t[i]-t[x]),每次转移都计算一遍显然是不划算的

容易发现这个问题对t数组做前缀和就能解决,化简一下公式就变成了:( (i - j) * t[i] - (sum[i] - sum[j]) ) *c+d。最后要注意longlong

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long
 5 using namespace std;
 6 
 7 const int mx = 1010;
 8 LL dp[mx], sum[mx], a[mx];
 9 
10 int main(){
11     int n;
12     LL d, c;
13     scanf("%d%lld%lld", &n, &d, &c);
14     memset(dp, 0x3f, sizeof dp);
15     for (int i = 1; i <= n; i++){
16         scanf("%lld", &a[i]);
17         sum[i] = sum[i-1]+a[i];
18     }
19     dp[0] = 0;
20     for (int i = 1; i <= n; i++)
21         for (int j = 0; j < i; j++)
22             dp[i] = min(dp[i], dp[j]+ c * ((i-j) * a[i] - (sum[i]-sum[j])) + d);
23     printf("%lld
", dp[n]);
24     return 0;
25 }

(i-j)

原文地址:https://www.cnblogs.com/QAQorz/p/9026530.html