• [LG4890]Never·island DP


    ~~~题面~~~

    题解:

      感到此题非常的神奇。。。看了大佬的题解才懂的。

      首先建模:

      先把所有队伍的出去回来时间都放在一个数组里,然后排序,从左到右扫一边,给每个队伍都建一个带权点,进行如下操作:

      (s表示出发,t表示回家, len表示两个点之间的时间差)  

      1,对于s --- > t的情况,如果两者属于一个队伍,那么给这个队伍加上len,表示如果给这个队伍钥匙可以获得的贡献。

        如果两者不属于同一个队伍,那么在这两个队伍之间连一条边权为len的边,表示如果同时给这2个队伍钥匙可以获得的贡献。

      2,对于s ---> s的情况,给左边的队伍加上len,表示如果给左边队伍钥匙可以获得的贡献。

      3,对于t ---> t的情况,给右边队伍加上len,表示如果给右边队伍钥匙可以获得的贡献。

      4,对于t ---> s的情况,直接给ans += len,因为不需要钥匙就可以获得这个贡献。

      然后考虑如何DP。

      我们观察到每个点最多只有一条入边,最多只有一条出边,因此这些点和边构成了由一堆链组成的图。而这些链两两不相交(不互相干扰)

      因此我们只需要保证在DP时,一条链中的点都按顺序放在一起即可。所以我们对整张图做一个拓扑排序,最后得到的DP顺序应该是类似这样的:(可能有点单独成链)

      相当于把所有链一一放好,然后DP。

      那么如何转移呢?

      设f[i][j][0/1]表示DP到i位,当前选了j个点,当前点选or不选的贡献。

      那么对于不相连的点,直接更新即可,

      对于相连的点,如果用f[i - 1][j - 1][1]更新f[i][j][1],那么还需要加上两点之间边的边权,表示两个点同时选带来的多余贡献。

      最后的答案等于ans = d[n * 2] - d[1] - ans - max(f[i][j][1], f[i][j][0]);

      d[n * 2] - d[1]是在获取整个线段的长度,减去ans是在减掉一开始就有的贡献(无需钥匙的),max(f[i][j][0], f[i][j][1])是给钥匙带来的贡献,相减后剩下的就是开门的天数。

      (一遍A,感到非常愉悦,而且速度还可以)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 2100
     5 #define ac 5000
     6 #define LL long long 
     7 
     8 int n, k, cnt, ans;
     9 int power[AC], Next[AC], last[AC];
    10 int in[AC], d[AC], tot;//存下DP序列
    11 LL s[AC], f[AC][AC][2];
    12 bool z[AC];
    13 //DP到i位,选了j个点,当前点选与不选,s是当前点的向后的边的边权
    14 struct node{
    15     int x, id;
    16     bool z;
    17 }p[ac];
    18 
    19 inline int read()
    20 {
    21     int x = 0;char c = getchar();
    22     while(c > '9' || c < '0') c = getchar();
    23     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    24     return x;
    25 }
    26 
    27 inline bool cmp(node a, node b)
    28 {
    29     return a.x < b.x;
    30 }
    31 
    32 inline void upmax(int &a, int b)
    33 {
    34     if(b > a) a = b;
    35 }
    36 
    37 void dfs(int x)
    38 {
    39     d[++tot] = x, z[x] = true;
    40     while(Next[x]) d[++tot] = Next[x], x = Next[x], z[x] = true;
    41 }
    42 
    43 void pre()
    44 {
    45     n = read(), k = read();
    46     for(R i = 1; i <= n; i ++)
    47     {
    48         p[++cnt] = (node){read(), i, 0};
    49         p[++cnt] = (node){read(), i, 1};
    50     }
    51     sort(p + 1, p + cnt + 1, cmp);
    52     int b = 2 * n;
    53     for(R i = 1; i < b; i ++)
    54     {
    55         int len = p[i + 1].x - p[i].x, x = p[i].id, y = p[i + 1].id;
    56         if(!p[i].z && p[i + 1].z)
    57         {
    58             if(x == y) power[p[i].id] += len;
    59             else Next[x] = y, last[y] = x, s[x] = len, ++ in[y];
    60         }    
    61         else if(!p[i].z && !p[i + 1].z) power[x] += len;
    62         else if(p[i].z && p[i + 1].z) power[y] += len;
    63         else ans += len;
    64     }
    65 }
    66 
    67 void work()
    68 {
    69     int b = 2 * n;
    70     for(R i = 1; i < b; i ++) //类似于拓扑排序,要没有入度才行
    71         if(!z[p[i].id] && !in[p[i].id]) dfs(p[i].id);
    72     for(R i = 1; i <= n; i ++)//枚举点
    73     {
    74         for(R j = 1; j <= k; j ++)
    75         {
    76             f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j][1]);
    77             if(last[d[i]]) f[i][j][1] = max(f[i - 1][j - 1][0], f[i - 1][j - 1][1] + s[last[d[i]]]) + power[d[i]];
    78             else f[i][j][1] = max(f[i - 1][j - 1][0], f[i - 1][j - 1][1]) + power[d[i]];
    79         }
    80     }
    81     printf("%lld
    ", p[n * 2].x - ans - p[1].x - max(f[n][k][1], f[n][k][0]));
    82 }
    83 
    84 int main()
    85 {
    86     freopen("in.in", "r", stdin);
    87     pre();
    88     work();
    89     fclose(stdin);
    90     return 0;
    91 }
    View Code
  • 相关阅读:
    菜鸟水平如何在Android Studio中添加uiautomator测试框架
    Android Studio入门问题汇总
    Win10上启动UICrawler自动遍历时报 "org.openqa.selenium.WebDriverException: An unknown server-side error occur red while processing the command. Original error: Could not sign with default certifi cate."
    python pip常用命令
    生动理解多态中向上与向下转型
    final 关键字的作用及应用案例
    如何使用 eclipse进行断点 debug 程序
    java中自己常犯的错误汇总
    Java中,类与类,类中的代码执行顺序
    Java中变量之局部变量、本类成员变量、父类成员变量的访问方法
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9778148.html
Copyright © 2020-2023  润新知