zoukankan      html  css  js  c++  java
  • Codeforces Round #536 (Div. 2)

    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是个定值,因此问题要麻烦一些,相当于物品体积是动态变化的,其实不难解决,按照题目中所给出的贪心规则,预处理出每一分钟的合法物品即可,这些合法物品的体积是固定的,接下来背包即可。

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

      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 }
  • 相关阅读:
    计算器类(C++&JAVA——表达式转换、运算、模板公式)
    使用/\_ 打印正三角形 C/C++
    Triangle2D类(Java)
    让键盘输入不影响界面的动态效果(C++)
    Java 7.21 游戏:豆机(C++&Java)
    Java 7.35 游戏:猜字游戏(C++&Java)
    Java 8.9 游戏:井字游戏(C++&Java)
    JAVA 8.20 游戏:四子连(Java&C++)
    简易Java文本编译器(C++)
    PAT 1089 狼人杀-简单版(20 分)(代码+测试点分析)
  • 原文地址:https://www.cnblogs.com/npugen/p/10799921.html
Copyright © 2011-2022 走看看