Codeforces 1107F(dp)
怎么就没人解释一下为啥用b排序可以保证正确性呢……太菜了,理解了好久。
时间流逝价值会丢失的背包,类似题洛谷1417
本题与洛谷1417不同之处在于流逝是有截止的。
1.这个dp[j]的含义是:最后跑路时欠了j个费所得到的最大钱数。
2.假设是不排序的,直接去背包,考虑两种转移,一种是选了当前这个以后到最后时欠的个数并不增多(即这个的k天都还了);另一种是这个也没还完。
3.如果直接都还了那顺序完全无所谓了,但是如果有这么几个都是最后要欠的,那么显然第一个要支付0天(即提钱当天就跑路了),第二个要支付1天,……第j个支付(j - 1)天。那么无论列一列式子(如洛谷1417)还是直观感受,反正就是这么几个,那肯定贪心地、尽量少扣大的b。这就是要按b从大到小排序的原因。
4.取dp[0~n]的最大值。
1 const int maxn = 550; 2 int n; 3 struct off { 4 ll a, b, k; 5 6 bool operator < (const off &rhs) const { 7 return b > rhs.b; 8 } 9 }offer[maxn]; 10 ll dp[maxn]; 11 12 int main() { 13 cin >> n; 14 rep(i, 1, n) cin >> offer[i].a >> offer[i].b >> offer[i].k; 15 16 sort(offer + 1, offer + 1 + n); 17 rep(i, 1, n) { 18 irep(j, i, 0) { 19 dp[j] = max(dp[j], dp[j] + offer[i].a - offer[i].b * offer[i].k); 20 if (j) dp[j] = max(dp[j], dp[j - 1] + offer[i].a - offer[i].b * (j - 1)); 21 } 22 } 23 24 cout << *max_element(dp, dp + n + 1) << endl; 25 return 0; 26 }