Codeforces Round #536 (Div. 2) - E. Lunar New Year and Red Envelopes(动态规划——01背包)

Problem  Codeforces Round #536 (Div. 2) - E. Lunar New Year and Red Envelopes

Time Limit: 3000 mSec

Problem Description

Input

 

Output

Output one integer — the minimum number of coins Bob would get if Alice disturbs him optimally.

Sample Input

5 0 2
1 3 4 5
2 5 5 8

Sample Output

13

题解:动态规划,看到题目的第一感觉是dp(i, j, 0/1),表示考虑前i个红包,打扰j次,并且第i个红包不选/选的最小硬币数,这样定义状态会有一个麻烦就是没有时间信息,而题目中说到每次选一个红包之后直到该红包对应的时间d这中间都不能拆其他红包,而我的状态定义没有涉及时间,无法考虑这种限制,导致状态转移无从谈起,再看看时间轴的长度同样是1e5,这就代表着我们可以将以红包为阶段改为以时间点为阶段,同时最后一个红包选不选这一维原意是为了解决采用填表法进行dp的转移问题(虽然没有解决),而如果我改为刷表法,就可以省去这一维,然后进行状态转移。

  以时间为阶段进行状态转移我在思考的时候遇到的困难就是如何处理每个红包所对应的 d 这个参数,怎么样体现出这一分钟选了,接下来直到d就都不能拆红包,解决方案是把从拆红包到d看作整体,也就是说当时间走到d时我才把硬币数加上去,而从当前时间 now 到 d 这中间的 dp(i, j)值都不用now这个时间点所拆的红包更新,这样对这些中间时间点来说其实是没有拆now这个红包的,换句话说,这些中间时间点是可以拆其他红包的,而被更新的是dp(d, j),这样一来,即便dp(d, j)还被从now到d 中间的dp值更新过,这些更新与dp(now, j)的更新都是不矛盾的,通过这样的方式我们就解决了d 这个参数的问题。当我想清楚这些后发现这个参数其实和背包问题的物品体积这个参数很像,如果我把d的含义改为拆了第i分钟的红包之后的d分钟内不能拆红包,那拆这一个红包是不是就相当于将时间轴上长度为d的一段占上。把时间轴总长度看作背包总体积,每个d看作每个物品的体积,这不就是个0/1背包么,这个题目由于d是个定值,因此问题要麻烦一些,相当于物品体积是动态变化的,其实不难解决,按照题目中所给出的贪心规则,预处理出每一分钟的合法物品即可,这些合法物品的体积是固定的,接下来背包即可。

  这道题最后能归到背包让人感到很精彩,经典模型之所以经典其中一个原因就是适用范围广,同时这也是对提炼模型的能力的锻炼。

扫描二维码关注公众号,回复: 6085742 查看本文章

  keep fighting!

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 #define REP(i, n) for (int i = 1; i <= (n); i++)
  6 #define sqr(x) ((x) * (x))
  7 
  8 const int maxn = 100000 + 100;
  9 const int maxm = 200000 + 100;
 10 const int maxs = 256;
 11 
 12 typedef long long LL;
 13 typedef pair<int, int> pii;
 14 typedef pair<double, double> pdd;
 15 
 16 const LL unit = 1LL;
 17 const int INF = 0x3f3f3f3f;
 18 const LL Inf = 0x3f3f3f3f3f3f3f3f;
 19 const double eps = 1e-14;
 20 const double inf = 1e15;
 21 const double pi = acos(-1.0);
 22 const LL mod = 1000000007;
 23 
 24 struct Node
 25 {
 26     int la, val, tag;
 27 
 28     Node(int la = 0, int val = 0, int tag = 0) : la(la), val(val), tag(tag) {}
 29 
 30     bool operator<(const Node &a) const
 31     {
 32         if (val == a.val)
 33         {
 34             return la > a.la;
 35         }
 36         else
 37         {
 38             return val > a.val;
 39         }
 40     }
 41 } node[maxn];
 42 
 43 int n, m, k;
 44 vector<Node> vec[maxn];
 45 map<Node, int> mmap;
 46 LL dp[2][maxn];
 47 
 48 int main()
 49 {
 50     ios::sync_with_stdio(false);
 51     cin.tie(0);
 52     //freopen("input.txt", "r", stdin);
 53     //freopen("output.txt", "w", stdout);
 54     cin >> n >> m >> k;
 55     int st, et, la, val;
 56     for (int i = 0; i < k; i++)
 57     {
 58         cin >> st >> et >> la >> val;
 59         vec[st].push_back((Node){la, val, 1});
 60         vec[et + 1].push_back((Node{la, val, -1}));
 61     }
 62     for (int i = 1; i <= n; i++)
 63     {
 64         for (auto item : vec[i])
 65         {
 66             if (item.tag == 1)
 67             {
 68                 if (mmap.count(item))
 69                 {
 70                     mmap[item]++;
 71                 }
 72                 else
 73                 {
 74                     mmap[item] = 1;
 75                 }
 76             }
 77             else
 78             {
 79                 mmap[item]--;
 80                 if (!mmap[item])
 81                 {
 82                     mmap.erase(item);
 83                 }
 84             }
 85         }
 86         if (!mmap.size())
 87         {
 88             node[i] = (Node){i, 0, 0};
 89         }
 90         else
 91         {
 92             node[i] = (*mmap.begin()).first;
 93         }
 94     }
 95     memset(dp, 0x3f, sizeof(dp));
 96     dp[0][1] = 0;
 97     LL ans = (unit << 60);
 98     for (int j = 0; j <= m; j++)
 99     {
100         int now = (j ^ 1) & 1;
101         int pre = (j & 1);
102         memset(dp[now], 0x3f, sizeof(dp[now]));
103         for (int i = 1; i <= n; i++)
104         {
105             dp[now][i + 1] = min(dp[now][i + 1], dp[pre][i]);
106             dp[pre][node[i].la + 1] = min(dp[pre][node[i].la + 1], dp[pre][i] + node[i].val);
107         }
108         ans = min(ans, dp[pre][n + 1]);
109     }
110     cout << ans << endl;
111     return 0;
112 }

猜你喜欢

转载自www.cnblogs.com/npugen/p/10799921.html