CF939F Cutlet 题解
题意简述
有一个正反面都为 \(0\) 的卡片,每过 \(1\) 分朝下那一面的数值就会增加 \(1\),你可以在几个区间的时间内翻转卡片,求经过 \(2n\) 秒后能否让这个卡片的正反面的数都为 \(n\),求最小翻转数。
暴力
为了简单起见,我们定义一面为正面,一面为反面,\(1\) 表示正面,\(0\) 表示反面。
一眼看出来 dp,\(dp_{i,j,1/0}\) 表示在第 \(i\) 个区间结束后,正面数字为 \(j\),\(1/0\) 面朝上的最小翻转数。
那么状态转移方程为:
\(dp_{i,j,1}=\min(dp_{i-1,j-p,1}+2,dp_{i-1,j-q,0}+1,dp_{i-1,j-g,1})\)
\(dp_{i,j,0}=\min(dp_{i-1,j-p,1}+1,dp_{i-1,j-q,0}+2,dp_{i-1,j,0})\)
其中满足:
区间间隔 \(\le p \le\) 两个区间右端点间隔。
区间长度 \(\le q \le\) 两个区间右端点间隔。
\(g\) 表示两个区间右端点间隔。
不难发现,这样的转移是 \(O(n)\) 的,再加上我们需要计算 \(nk\) 个 dp 值,这样做显然超时。需要考虑优化。
优化
不难发现,在计算一个区间完成后的值时,如果我们从 \(n\) 到 \(0\) 来计算,每次计算值所需要遍历区间的上限和下限都时逐渐减少的,那么我们就可以采取单调队列优化了。
这里用到一个小技巧:
如果一开始遍历区间的下限不为最低,那么我们可以令一个变量 \(idx\) 一开始指向第一个区间的下限,然后逐渐降低,分批入队。
这个单调队列可以滚动掉一维,只需要保留它记录 dp 值的 \(0/1\) 就行了。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, K = 110, INF = 0x3f3f3f3f;
int dp[K][N * 2][2];
int g[K], n, k, idx[2];
deque <int> q[2];
struct line {
int l, r;
bool operator < (const line& rhs) const {
return l < rhs.l;
}
}lines[K];
inline void q_push (int i, int j, int op) {
while (q[op].size() && dp[i][q[op].back()][op] >= dp[i][j][op]) q[op].pop_back();
q[op].push_back(j);
}
inline void q_pop (int i, int j, int op) {
while (q[op].size() && j - q[op].front() < 0) q[op].pop_front();
}
inline void init () {
q[1].clear(); q[0].clear();
idx[0] = idx[1] = 2 * n;
}
int main () {
memset(dp, INF, sizeof(dp));
scanf("%d%d", &n, &k);
for (int i = 1;i <= k;i++) scanf("%d%d", &lines[i].l, &lines[i].r);
sort(lines + 1, lines + 1 + k);
g[1] = lines[1].l; g[k + 1] = 2 * n - lines[k].r;
for (int i = 2;i <= k;i++) g[i] = lines[i].l - lines[i - 1].r;
for (int j = lines[1].l;j <= lines[1].r;j++) {
dp[1][j][1] = 2;
dp[1][j][0] = 1;
}
dp[1][lines[1].r][1] = 0;
for (int i = 2;i <= k;i++) {
int l = lines[i].r - lines[i - 1].r, lg = lines[i].r - lines[i].l;
init();
for (int j = lines[i].r;j >= 0;j--) {
while (j - l <= idx[1] && idx[1] > 0) q_push(i - 1, idx[1]--, 1);
while (j - lg <= idx[0] && idx[0] > 0) q_push(i - 1, idx[0]--, 0);
q_pop(i - 1, j - g[i], 1); q_pop(i - 1, j, 0);
dp[i][j][1] = min(dp[i][j][1], (q[1].size() ? dp[i - 1][q[1].front()][1] + 2 : INF));
dp[i][j][1] = min(dp[i][j][1], (q[0].size() ? dp[i - 1][q[0].front()][0] + 1 : INF));
dp[i][j][1] = min(dp[i][j][1], (j - l >= 0 ? dp[i - 1][j - l][1] : INF));
// cout << i << " " << j << " 1: " << dp[i][j][1] << endl;
}
init();
for (int j = lines[i].r;j >= 0;j--) {
while (j - l <= idx[1] && idx[1] > 0) q_push(i - 1, idx[1]--, 1);
while (j - lg <= idx[0] && idx[0] > 0) q_push(i - 1, idx[0]--, 0);
q_pop(i - 1, j - g[i], 1); q_pop(i - 1, j, 0);
dp[i][j][0] = min(dp[i][j][0], (q[1].size() ? dp[i - 1][q[1].front()][1] + 1 : INF));
dp[i][j][0] = min(dp[i][j][0], (q[0].size() ? dp[i - 1][q[0].front()][0] + 2 : INF));
dp[i][j][0] = min(dp[i][j][0], dp[i - 1][j][0]);
// cout << i << " " << j << " 0: " << dp[i][j][0] << endl;
}
}
if (min(n - g[k + 1] >= 0 ? dp[k][n - g[k + 1]][1] : INF, dp[k][n][0]) < INF) printf("Full\n%d\n", min(n - g[k + 1] >= 0 ? dp[k][n - g[k + 1]][1] : INF, dp[k][n][0]));
else printf("Hungry\n");
return 0;
}
CF939F Cutlet 题解的更多相关文章
- CF939F Cutlet (单调队列优化DP)
题目大意:要煎一块有两个面的肉,只能在一段k不相交的时间段$[l_{i},r_{i}]$内翻转,求$2*n$秒后,保证两个面煎的时间一样长时,需要最少的翻转次数,$n<=100000$,$k&l ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
随机推荐
- 2021-05-14:给定一个数组arr,想知道arr中哪两个数的异或结果最大。返回最大的异或结果。
2021-05-14:给定一个数组arr,想知道arr中哪两个数的异或结果最大.返回最大的异或结果. 福大大 答案2021-05-14: 前缀树.一个数,用二进制表示,0走左边分支,1走右边分支.准备 ...
- 2021-10-22:颠倒二进制位。颠倒给定的 32 位无符号整数的二进制位。提示:请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不
2021-10-22:颠倒二进制位.颠倒给定的 32 位无符号整数的二进制位.提示:请注意,在某些语言(如 Java)中,没有无符号整数类型.在这种情况下,输入和输出都将被指定为有符号整数类型,并且不 ...
- vue全家桶进阶之路26:Vue.js 3.0与Vue.js 2.x 的比较和注意事项
Vue.js 3.0 是 Vue.js 框架的最新版本,于 2020 年 9 月正式发布.Vue.js 3.0 主要的改进和新特性包括: 更好的性能:Vue.js 3.0 使用了更快的虚拟 DOM 实 ...
- 一些JS过滤方法
一般过滤器我们都会卸载过滤filter文件内 本文这里就直接写正常methods格式的 //过滤空格 filterSpaces(data) { return data.replace(/\s+/g, ...
- 7-8 估值一亿的AI核心代码
题目描述: 以上图片来自新浪微博. 本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是: 无论用户说什么,首先把对方说的话在一行中原样打印出来: 消除原文中多余空格:把相邻单词间的多个空格 ...
- HTML转为PDF,图片导出失败的终极解决方案
如题项目有需求将一个页面导出为pdf,然而页面中的图片却始终无法导出成功 文章目录 一.导出的方法 二.初步测试的结果 三.使用f12查找原油 四.方案一 五.方案二 六.方案三 七.完整代码 1.使 ...
- 生物信息培训之WGCNA-权重基因共表达网络分析
本文分享自微信公众号 - 生信科技爱好者(bioitee).如有侵权,请联系 support@oschina.cn 删除.本文参与"OSC源创计划",欢迎正在阅读的你也加入,一起分 ...
- 安卓第一课:gradle仓库的导入
今天装好android studio,结果刚进入就报错了: SSL peer shut down incorrectly 读注释发现原来是gradle下载文件不成功.果然,原来是vpn掉线了,上网查了 ...
- 爬取豆瓣Top250图书数据
爬取豆瓣Top250图书数据 项目的实现步骤 1.项目结构 2.获取网页数据 3.提取网页中的关键信息 4.保存数据 1.项目结构 2.获取网页数据 对应的网址为https://book.douban ...
- vivo 帐号服务稳定性建设之路-平台产品系列06
作者:vivo 互联网平台产品研发团队- Shi Jianhua.Sun Song 帐号是一个核心的基础服务,对于基础服务而言稳定性就是生命线.在这篇文章中,将与大家分享我们在帐号稳定性建设方面的经验 ...