F. Mattress Run 题解
F. Mattress Run
挺好的一道题,对于DP的本质的理解有很大的帮助。
首先要想到的就是将这个拆成两个题,一个dp光求获得足够的夜晚的最小代价,一个dp光求获得足够的停留的最小代价。
显然由于这个题需要存储的信息很大,我们设状态时就要思考如何才能在规定的时间内完成而不超时。
请求有5000个,若设与请求有关的状态,例如:我们设f[i][j],表示当前在请求i,获得的资格j的最小代价,确实,因为我们知道了请求i的所有信息,包括结束时间,所在的旅馆号的信息,但在状态转移时,难免要枚举上一次的请求所在的位置,50005000,别忘了还有j的枚举再50,这样就爆了,别报侥幸心理,这个题输出方案加上你dp要做两边,常数巨大。那么考虑重新设计状态,考虑到转移时,实际上若上一次的天数不为a[i].l,我们根本不用在意他在哪个旅馆,当上一次的天数恰好为a[i].l时,我们才考虑他的旅馆。那么我们可以将天数和旅馆都设在状态里,设f[i][j][k]表示在第i天在旅馆j获得的资格为k的最小代价。先枚举请求,然后考虑每个请求会使得哪些状态发生改变,状态转移时,为了优化,我们令设dp[i][j]表示在第i天获得资格j的最小代价,方便我们省去枚举的旅馆数,之后我们另外讨论天数为a[i].l的情况即可。复杂度为500036550,轻松跑过,输出方案的话,我们大可用结构体来记录当前状态由哪一个转态得来。之后逆推一下即可。
#include<bits/stdc++.h>
using namespace std;
int n,s[2],h,m,c[5005],num;
int f[370][52][52][2],dp[370][52][2];
struct ss{int x,y,z;}Z[370][52][52][2],S[370][52][2];
//设f[i][j][k]表示第i天在j号旅馆获得的资格为k的最小代价,
//dp[i][j]表示第i天获得的资格为j的最小代价。
struct wy{int l,r,val,id,qid;}a[5005];
inline bool cmp(wy a,wy b)
{
return a.l<b.l;
}
inline void solve(int op)
{
f[0][0][0][op]=0;dp[0][0][op]=0;
for(int i=1;i<=m;++i)//枚举所有的请求。
{//转移来的天数分为两类,一类小于l,一类等于l
for(int j=0;j<a[i].l;++j)//枚举所有可以改变的状态的天数
for(int k=0;k<=s[op];++k)
{
int d=min((op==0?k+a[i].r-a[i].l:k+1),s[op]);
if(dp[j][k][op]+a[i].val<f[a[i].r][a[i].id][d][op])
{
f[a[i].r][a[i].id][d][op]=dp[j][k][op]+a[i].val;
Z[a[i].r][a[i].id][d][op]=S[j][k][op];
}
if(f[a[i].r][a[i].id][d][op]<dp[a[i].r][d][op])
{
dp[a[i].r][d][op]=f[a[i].r][a[i].id][d][op];
S[a[i].r][d][op]={a[i].r,a[i].id,d};
}
}
for(int j=0;j<=h;++j) //等于l的,枚举从那个旅馆过来
{
if(j==a[i].id) continue;
for(int k=0;k<=s[op];++k) //枚举上一次的状态。
{
int d=min((op==0?k+a[i].r-a[i].l:k+1),s[op]);
if(f[a[i].l][j][k][op]+a[i].val<f[a[i].r][a[i].id][d][op])
{
f[a[i].r][a[i].id][d][op]=f[a[i].l][j][k][op]+a[i].val;
Z[a[i].r][a[i].id][d][op]=(ss){a[i].l,j,k};
}
if(f[a[i].r][a[i].id][d][op]<dp[a[i].r][d][op])
{
dp[a[i].r][d][op]=f[a[i].r][a[i].id][d][op];
S[a[i].r][d][op]={a[i].r,a[i].id,d};
}
}
}
}
}
inline void work(ss x,int op)
{
if(x.x==0||x.y==0||x.z==0) return;
for(int i=1;i<=m;++i)
{
if(a[i].r==x.x&&a[i].id==x.y)
{
ss k=Z[x.x][x.y][x.z][op];
int d=min((op==0?k.z+a[i].r-a[i].l:k.z+1),s[op]);
if(d==x.z&&f[x.x][x.y][x.z][op]-a[i].val==f[k.x][k.y][k.z][op])
{
c[++num]=a[i].qid;
work(k,op);
return;
}
}
}
}
int main()
{
//freopen("1.in","r",stdin);
scanf("%d%d%d%d%d",&n,&s[0],&s[1],&h,&m);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d%d",&a[i].id,&a[i].l,&a[i].r,&a[i].val);
a[i].qid=i;
}
sort(a+1,a+m+1,cmp);
memset(f,0x3f,sizeof(f));
memset(dp,0x3f,sizeof(dp));
solve(0);solve(1);
int ans1=1e9,ans2=1e9,o1,o2;
for(int i=0;i<=n;++i)
{
if(dp[i][s[0]][0]<ans1)
{
ans1=dp[i][s[0]][0];
o1=i;
}
if(dp[i][s[1]][1]<ans2)
{
ans2=dp[i][s[1]][1];
o2=i;
}
}
if(min(ans1,ans2)==1e9) {puts("IMPOSSIBLE");return 0;}
else if(ans1<=ans2) work(S[o1][s[0]][0],0),puts("NIGHTS");
else if(ans1>ans2) work(S[o2][s[1]][1],1),puts("STAYS");
printf("%d\n",num);
for(int i=num;i>=1;--i) printf("%d ",c[i]);
return 0;
}
人一旦有了自信,就拥有了一切!
F. Mattress Run 题解的更多相关文章
- Codeforces Round #624 (Div. 3) F. Moving Points 题解
第一次写博客 ,请多指教! 翻了翻前面的题解发现都是用树状数组来做,这里更新一个 线段树+离散化的做法: 其实这道题是没有必要用线段树的,树状数组就能够解决.但是个人感觉把线段树用熟了会比树状数组更有 ...
- LuoguP5139 z小f的函数 题解
Content 给定 \(T\) 个二次函数 \(y=ax^2+bx+c\),有若干次操作,有一个操作编号 \(p\),保证仅为以下这五种: 操作 \(1\):给定 \(k\),将函数图像向上移动 \ ...
- HDU X mod f(x)(题解注释)
X mod f(x) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 合肥学院ACM集训队第一届暑假友谊赛 B FYZ的求婚之旅 D 计算机科学家 F 智慧码 题解
比赛网址:https://ac.nowcoder.com/acm/contest/994#question B FYZ的求婚之旅 思路: 然后用快速幂即可. 细节见代码: #include <i ...
- Grazing on the Run 题解
[题目大意] 大致题意就是,你的初始坐标为\(x\),你要去数轴上的\(n\)个点,问你到达所有点的时间总和最小是多少. 直接贪心肯定不行,所以考虑\(DP\) 先把坐标离散(也就是预处理两点距离\( ...
- 2018年第九届蓝桥杯【C++省赛B组】B、C、D、F、G 题解
B. 明码 #STL 题意 把每个字节转为2进制表示,1表示墨迹,0表示底色.每行2个字节,一共16行,布局是: 第1字节,第2字节 第3字节,第4字节 .... 第31字节, 第32字节 给定一段由 ...
- LuoguB2147 求 f(x,n) 题解
Content 求给定 \(x,n\),求 \(f(x,n)=\sqrt{n+\sqrt{(n-1)+\sqrt{(n-2)+\sqrt{\dots+2+\sqrt{1+x}}}}}\) 的值. So ...
- 【AtCoder】ARC097 (C - F)题解
C - K-th Substring 题解 找出第K大的子串,重复的不计入 这个数据范围可能有什么暴力可以艹过去吧,但是K放大的话这就是后缀自动机板子题啊= = 代码 #include <ios ...
- BZOJ 一句话题解
菜鸡刷题记录 [题号:题解] 1008:简单排列组合 #include <bits/stdc++.h> using namespace std; #define ll long long ...
随机推荐
- 洛谷P1090——合并果子(贪心)
https://www.luogu.org/problem/show?pid=1090 题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合 ...
- SpringCloud 学习总结
SpringCloud 学习总结 学习回顾 1.Maven依赖管理 在微服务项目中,我们一般是先创建一个父项目模块对整个项目的依赖进行版本限定和依赖控制,子模块继承父模块后,不需要再考虑版本和依赖 ...
- PHP的bz2压缩扩展工具
在日常的开发和电脑使用中,我们经常会接触到压缩和解压的一些工具,PHP 也为我们准备了很多相关的操作扩展包,都有直接可用的函数能够方便的操作一些压缩解压功能.今天,我们先学习一个比较简单但不太常用的压 ...
- 判断手机浏览器还是微信浏览器(PHP)
//判断是否 微信浏览器 function isWeixin1() { if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== fa ...
- 新环境c7、php7.4、openssl1.1.1g,再discuz里发送邮件总是报ssl连接不上
Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL r ...
- dede调用文章内第一张原始图片(非缩略图)的实现方法
第一步,修改include/extend.func.php文件,最下面插入函数,查询的是文章附加表,如需查询图片集什么的,改表名即可 //取原图地址 function GetFirstImg($arc ...
- Docker系列(14)- Portainer可视化面板安装
官网 https://documentation.portainer.io/v2.0-be/deploy/beinstalldocker/ 可视化 portainer docker run -d -p ...
- 一朵云、一张网、一体化 ——GRTN 打造最佳流媒体场景实践
阿里巴巴 GRTN 是面向流媒体云原生设计的,方便客户构建自己的流媒体云原生应用,让流媒体服务无处不在. 在近期召开的分布式云主题报告会上,阿里云资深技术专家卢日发表了题为<GRTN 打造阿里云 ...
- python刷题第四周
本周有所收获的题目: 第一题: 第4章-17 水仙花数(20 分) (20 分) 水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身. 例如:153=1×1×1+5×5×5 ...
- Windows环境下实现WireShark抓取HTTPS
https 加密传输,Wireshark 没有设置的情况下是没有办法抓到包的 https 的数据包. 设置系统环境变量(SSLKEYLOGFILE) WireShark 设置 SSL 选项 参考文章: ...