CF939F
好神奇的dp...
首先有一个很简单的思想:设dp[i][j]表示目前到了第i分钟,朝上的面被烤了j分钟的情况下所需的最小交换次数
那么有转移:dp[i][j]=min(dp[i-1][j],dp[i-1][i-j]+1)
这一点很好理解,就是讨论现在向上这面上一分钟的状态:如果上一分钟这一面也朝上,那么就直接继承,如果上一分钟这一面朝下,那么就要翻一次,同时之前朝上的面的被烤的时间就是i-j
但这个转移显然是O(n^2)的,这样做过不去这道题。
所以我们考虑优化
可是,这个转移在某种意义上已经达到了最优,所以不太好优化了...
那么我们只能重构状态
我们发现,能对肉进行翻面的时间只有这k个给定的时间段,且k<=100,那么我们考虑:能否把一个时间段整体更新,将时间复杂度降成O(nk)呢?
这样我们必须重新设计状态:记状态dp[i][j]表示目前到了第i个时间段的结尾,朝上这一面的肉被烤的时间为j
那么我们就要重新考虑转移:
首先我们观察一下规律:
可以发现:在一段可以翻转的区间内,真正翻转的次数只可能有0,1或2三种,所以我们只需按这三种情况分别讨论转移即可
(关于上面这句话的解释:如果你翻转了三次或更多,那么你一定可以将某几次翻转合并后变成上述情况,也就是说上述情况就足够覆盖所有状态)
翻转次数为0的情况很好判断,直接继承上一次的状态即可
如果翻转次数为2,那么这相当于原来朝上的面现在还朝上,原来朝下的面现在还朝下,只是中途把朝上的面翻过去烤了一下而已。
那么我们可以枚举在之前朝上的面在这一段时间内被烤的时间k,那么在这段区间之前这一面被烤的之间就是j-k
于是可以进行转移:dp[i][j]=min(dp[i-1][j-k]+2)
但是这样做显然时间不够优越,所以我们要采取策略来优化!
我们推一发式子:
设,那么:
发现这样的形式就可以用单调队列维护了。
从小向大枚举j,然后推进单调队列中维护即可
至于翻转次数为1的情况,相当于现在朝上的面原先朝下,那么如果现在朝上的面被烤的时间为j,枚举现在朝下的面在这一区间内被烤的时间为k,那么r-j就是现在朝下的面被烤的时间,而我们枚举了朝下的面在这一区间内被烤的时间为k,那么在进入这一区间之前现在朝下的面原来朝上,已经被烤过的时间就是r-j-k!
这样有转移:dp[i][j]=min(dp[i-1][r-j-k])+1!
用类似上述的方法,同样构造单调队列转移,注意此时要倒序枚举,因为我们枚举的东西事实上起到的是j+k的作用,所以r-枚举的东西就要倒序
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int dp[2][1000005];
int que[1000005];
int n,k;
int main()
{
scanf("%d%d",&n,&k);
int now=1,past=0;
memset(dp[past],0x3f,sizeof(dp[past]));
dp[0][0]=0;
while(k--)
{
memcpy(dp[now],dp[past],sizeof(dp[now]));
int l,r;
scanf("%d%d",&l,&r);
int head=1,tail=0;
for(int i=0;i<=min(n,r);i++)
{
while(head<=tail&&dp[past][que[tail]]>=dp[past][i])
{
tail--;
}
que[++tail]=i;
while(head<=tail&&que[head]<i-(r-l))
{
head++;
}
dp[now][i]=min(dp[now][i],dp[past][que[head]]+2);
}
head=1,tail=0;
for(int i=r;i>=0;i--)
{
while(head<=tail&&dp[past][que[tail]]>=dp[past][r-i])
{
tail--;
}
while(head<=tail&&que[head]<l-i)
{
head++;
}
que[++tail]=r-i;
dp[now][i]=min(dp[now][i],dp[past][que[head]]+1);
}
swap(now,past);
}
if(dp[past][n]>=0x3f3f3f3f)
{
printf("Hungry\n");
}else
{
printf("Full\n%d\n",dp[past][n]);
}
return 0;
}
CF939F的更多相关文章
- CF939F Cutlet (单调队列优化DP)
题目大意:要煎一块有两个面的肉,只能在一段k不相交的时间段$[l_{i},r_{i}]$内翻转,求$2*n$秒后,保证两个面煎的时间一样长时,需要最少的翻转次数,$n<=100000$,$k&l ...
随机推荐
- printf是在libc库中么?
libc中果然有很多的函数,使用nm看了一下,里面竟然还有reboot函数,汗! 使用grep,可以看到各种 printf 也都在这里头. objdump是看函数的地址与函数名对应的,虽然也能证明pr ...
- 前端必备——js中前端与后台的数据交互全解
只要编程语言能够支持网卡端口的监听和发送,理论上都是可以实现服务器后台设计的.也因此造成了实现后台的语言偏多,而web前端语言以html/css/js为主.所以在这里我们不涉及后台的设计,只介绍在we ...
- 通用redis命令
Redis五种数据类型,String,hash,list,set,有序set keys pattern:获取所有与pattern匹配的key,返回所有与该key匹配的keys. 通配符: *表示任意0 ...
- 使用WireMock快速伪造RESTful服务
⒈下载WireMock独立运行程序 http://wiremock.org/docs/running-standalone/ ⒉运行 java -jar wiremock-standalone-2.2 ...
- 巧用这19条MySQL优化【转】
1.EXPLAIN 做MySQL优化,我们要善用EXPLAIN查看SQL执行计划. 下面来个简单的示例,标注(1.2.3.4.5)我们要重点关注的数据: type列,连接类型.一个好的SQL语句至少要 ...
- nginx Access-Control-Allow-Origin css跨域
问题原因:nginx 服务器 css 字体跨域 以及img相对路径 问题 描述:用nginx做页面静态化时遇到了两个问题 1.我有两个静态资源服务器 static.xxx.com 和 item.xx ...
- 解决win10中chm内容显示为空白的问题
在win10中打开chm文件,一般会是这个效果,内容显示为空白: 解决这个问题的方法是,在打开chm文件时,会有个安全警告的询问对话框,如下: 将[打开此文件前总是询问(W)]复选框的勾去掉,就OK了 ...
- bzoj 1175: The stairways of Saharna
一道杨氏矩阵的题,萌新初入门,还不是很懂,这篇 blog 讲的超级好(就是看图有点麻烦) 据说这玩意儿可以代替堆和平衡树用,支持插入.删除.查询,跑得还挺快的(慢着,复杂度好像是 n^2 ? 而且空间 ...
- 004_strace工具
strace - trace system calls and signals 一.strace工具详解 之前线上主机上8351 进程夯死导致无法获悉进程信息,监控程序使用ps 命令查看进程信息至/p ...
- 009_关闭linux的THP
背景:公司某个大型业务系统反馈最近数据库服务器总是宕机(此处描述不准确,后面解释),最后,客户.运维人员都觉得实在是忍无可忍了,项目经理打电话找到我问是否能帮忙诊断一下,刚好第二天要去现场沟通另外一个 ...