[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,感到非常愉悦,而且速度还可以)
#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的更多相关文章
- 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 ...
- CodeForces 540D Bad Luck Island (DP)
题意:一个岛上有石头,剪刀和布,规则就不用说了,问你最后只剩下每一种的概率是多少. 析:很明显的一个概率DP,用d[i][j][k]表示,石头剩下 i 个,剪刀剩下 j 个,布剩下 k 个,d[r][ ...
- HDU-3502-Huson'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 ...
- bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1826 Solved: 405[Submit][S ...
- P4890 Never·island(dp)
P4890 Never·island 求门开的最小时间,其实也就是求门关的最大时间. 坐标这么大....显然坐标要离散化 离散化排序后,我们发现x轴被这些点划分成若干条线段$(l,r)$,并且有4种情 ...
- P4381 [IOI2008]Island(基环树+单调队列优化dp)
P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...
- 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 ...
- CF#301 D:Bad Luck Island (概率dp)
D:Bad Luck Island 一个岛上有r个石头,s个剪子,p个布,他们之间随机挑出两个相遇,如果不是相同物种,就会有一个消失,分别求出最后这座岛上只剩下一个物种的概率. 我们用dp[i][j] ...
- CF 540D——Bad Luck Island——————【概率dp】
Bad Luck Island time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...
随机推荐
- mac 安装requests
首先mac上已经安装了python,我的是python2x,我自己安装了python3,python3安装requests,控制台,输入,pip3 install requests 下面就已经安装完成 ...
- python 装饰器 回顾 及练习
# 复习 # 讲作业 # 装饰器的进阶 # functools.wraps # 带参数的装饰器 # 多个装饰器装饰同一个函数 # 周末的作业 # 文件操作 # 字符串处理 # 输入输出 # 流程控制 ...
- .NET CORE LOG
.NET CORE LOG 合格的应用程序不仅要求运行的高效和计算的准确,稳定及可靠性也要得到满足,同事,系统的可维护性也相当重要.谈及到可维护性,就必须涉及到系统运行状态的监控和异常的快速定位与跟踪 ...
- python pip ,安装,卸载,查看等命令,不同版本
pycharm及python的使用说明 Python和 pycharm的使用 1. pycharm和Python 下载 安装后需要激活码.判断Python是否安装好了,cmd下跑: python ...
- JAVA多进程入门
概念 并行和并发 并行:物理上的实现,在同一时间点上发生 并发:两个事件在一个时间段内发生,如单片机的单核多线程 进程和线程 进程:一个应用程序可以有多个进程,每一个进程有一个独立的内存空间 线程:一 ...
- @Transactional spring 事务失效(转载)
原文地址:http://hwak.iteye.com/blog/1611970 1. 在需要事务管理的地方加@Transactional 注解.@Transactional 注解可以被应用于接口定义和 ...
- mysql字符串拼接,存储过程
添加字段: alter table `user_movement_log`Add column GatewayId int not null default 0 AFTER `Regionid` (在 ...
- .net core 新建一个web api 的步骤 初级
1.使用VS2017 选择 .net core web应用程序. 2.选择web api(空). 3.如果需要用iis express调试,则需要修改 program.cs. 4.在Controlle ...
- Coap协议学习笔记-第一篇
1. 物联网应用上一般使用单片机(或者其他SOC),单片机的RAM内存一般只有20KB~~128KB左右,然而一个TCP协议栈可能就20KB,所以只能用UDP,因为UDP相对小很多,然后在UDP上加了 ...
- 字符串分割(C++)
一.用strtok函数进行字符串分割 原型: char *strtok(char *str, const char *delim); 功能:分解字符串为一组字符串. 参数说明:str为要分解的字符串, ...