~~~题面~~~

题解:

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

  首先建模:

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

  (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,感到非常愉悦,而且速度还可以)

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 2100
#define ac 5000
#define LL long long int n, k, cnt, ans;
int power[AC], Next[AC], last[AC];
int in[AC], d[AC], tot;//存下DP序列
LL s[AC], f[AC][AC][];
bool z[AC];
//DP到i位,选了j个点,当前点选与不选,s是当前点的向后的边的边权
struct node{
int x, id;
bool z;
}p[ac]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline bool cmp(node a, node b)
{
return a.x < b.x;
} inline void upmax(int &a, int b)
{
if(b > a) a = b;
} void dfs(int x)
{
d[++tot] = x, z[x] = true;
while(Next[x]) d[++tot] = Next[x], x = Next[x], z[x] = true;
} void pre()
{
n = read(), k = read();
for(R i = ; i <= n; i ++)
{
p[++cnt] = (node){read(), i, };
p[++cnt] = (node){read(), i, };
}
sort(p + , p + cnt + , cmp);
int b = * n;
for(R i = ; i < b; i ++)
{
int len = p[i + ].x - p[i].x, x = p[i].id, y = p[i + ].id;
if(!p[i].z && p[i + ].z)
{
if(x == y) power[p[i].id] += len;
else Next[x] = y, last[y] = x, s[x] = len, ++ in[y];
}
else if(!p[i].z && !p[i + ].z) power[x] += len;
else if(p[i].z && p[i + ].z) power[y] += len;
else ans += len;
}
} void work()
{
int b = * n;
for(R i = ; i < b; i ++) //类似于拓扑排序,要没有入度才行
if(!z[p[i].id] && !in[p[i].id]) dfs(p[i].id);
for(R i = ; i <= n; i ++)//枚举点
{
for(R j = ; j <= k; j ++)
{
f[i][j][] = max(f[i - ][j][], f[i - ][j][]);
if(last[d[i]]) f[i][j][] = max(f[i - ][j - ][], f[i - ][j - ][] + s[last[d[i]]]) + power[d[i]];
else f[i][j][] = max(f[i - ][j - ][], f[i - ][j - ][]) + power[d[i]];
}
}
printf("%lld\n", p[n * ].x - ans - p[].x - max(f[n][k][], f[n][k][]));
} int main()
{
freopen("in.in", "r", stdin);
pre();
work();
fclose(stdin);
return ;
}

[LG4890]Never·island DP的更多相关文章

  1. cf.301.D. Bad Luck Island(dp + probabilities)

    D. Bad Luck Island time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  2. CodeForces 540D Bad Luck Island (DP)

    题意:一个岛上有石头,剪刀和布,规则就不用说了,问你最后只剩下每一种的概率是多少. 析:很明显的一个概率DP,用d[i][j][k]表示,石头剩下 i 个,剪刀剩下 j 个,布剩下 k 个,d[r][ ...

  3. HDU-3502-Huson&#39;s Adventure Island(BFS+如压力DP)

    Problem Description A few days ago, Tom was tired of all the PC-games, so he went back to some old F ...

  4. bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp

    1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1826  Solved: 405[Submit][S ...

  5. P4890 Never·island(dp)

    P4890 Never·island 求门开的最小时间,其实也就是求门关的最大时间. 坐标这么大....显然坐标要离散化 离散化排序后,我们发现x轴被这些点划分成若干条线段$(l,r)$,并且有4种情 ...

  6. P4381 [IOI2008]Island(基环树+单调队列优化dp)

    P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...

  7. Codeforces Round #301 (Div. 2) D. Bad Luck Island 概率DP

    D. Bad Luck Island Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/540/pr ...

  8. CF#301 D:Bad Luck Island (概率dp)

    D:Bad Luck Island 一个岛上有r个石头,s个剪子,p个布,他们之间随机挑出两个相遇,如果不是相同物种,就会有一个消失,分别求出最后这座岛上只剩下一个物种的概率. 我们用dp[i][j] ...

  9. CF 540D——Bad Luck Island——————【概率dp】

    Bad Luck Island time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

随机推荐

  1. jquery点击按钮复制内容

    做移动端的项目遇到一个需求要点击按钮复制dom里的内容,看了很多资料显示必须textarea或者input里的内容才能简单复制,还有就是用插件的了,最终都因为遇到各种问题放弃,最终选择了最简单的点击复 ...

  2. javascript中几种this指向问题

    javascript中几种this指向问题   首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用   函数作为全局对象调用,this指向 ...

  3. pyqt5通过qt designer 设计方式连接多个UI图形界面

    当我们通过pyqt开发时,eric6为我们提供了一个方便的工具:图形化的绘制UI工具--qtdesigner.我们可以通过它开发多个UI,然后利用信号-槽工具,将功能代码附着在上面.也可以将多个界面连 ...

  4. WordPress博客插件程序:搜索下拉框openSug

    百度搜索框下拉提示Wordpress组插件. 下载地址:https://www.opensug.org/faq/wp-content/uploads/2018/12/opensug.wordpress ...

  5. 微信小程序中无刷新修改

    1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就 ...

  6. hive 学习系列五(hive 和elasticsearch 的交互,很详细哦,我又来吹liubi了)

    hive 操作elasticsearch 一,从hive 表格向elasticsearch 导入数据 1,首先,创建elasticsearch 索引,索引如下 curl -XPUT '10.81.17 ...

  7. 《python编程从入门到实践》第六章笔记

    1.字典 字典:一系列键-值对,每一个键都与每一个值相关联.与键相关联的值可以是数字.字符串.列表和字典. 最简单的字典只有一个键值对. eg: alien = {'color':'green','p ...

  8. fopen,fwrite,fread使用

    fopen, fwrite, fread详解 1.头文件 #include <stdio.h> 2.fopen (1) 函数原型 FILE *fopen(char *filename, * ...

  9. (长期更新)OI常用模板

    代码很简单的模板就不收录了. DFT 离散傅立叶变换 void dft(pdd *a,int l,bool r){ int i,j=l/2,k; for(i=1;i<l;++i){ if(i&l ...

  10. python2.7入门---变量类型&案例

      这篇文章呢,主要是用来记录python中的变量类型学习内容的.接下来就来看一下变量类型,那么什么是变量呢.变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间.基于变量的数据类型,解 ...