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 ...
随机推荐
- Elasticsearch的基本使用
1. 概述 之前聊了一下 Elasticsearch 的安装,今天我们来说说 Elasticsearch 的基本使用. 2. Elasticsearch索引的使用 索引(index)相当于是mysql ...
- 一文看懂String类中的常用方法
1.int length(): 返回字符串的长度: return value.length 2.char charAt(int index): 返回某索引处的字符return value[index] ...
- SpringCloudAlibaba - 整合 Nacos 实现服务注册与发现
目录 前言 环境 Nacos是什么? 服务发现原理 搭建 Nacos Server Nacos Server 下载地址 Nacos Server 的版本选择 运行 Nacos Server Nacos ...
- js相同的正则多次调用test()返回的值却不同的问题
js代码: var name = '测试中文';// 姓名 var nameRgexp = new RegExp("[a-zA-Z\u4e00-\u9fa5]{2,}"," ...
- chrome 的手机调试工具 toggle device toolbar
chrome 的手机调试工具 toggle device toolbar 是否可以模拟到不同系统,如苹果系统和安卓系统.
- mysql 优化的相关配置:总结中...
centos 为例:mysql 怎么获取配置参数信息: /etc/my.cnf; /etc/myql/my.cnf/; 家目录:或者指定目录:作用域 客户端:全局 set global 会话 set[ ...
- P6091-[模板]原根
正题 题目链接:https://www.luogu.com.cn/problem/P6091 题目大意 给出一个数\(p\),求出它的所有在\([0,p]\)的原根. 解题思路 原根的定义,\(\de ...
- 03 依赖注入--01控制反转、IoC模式
控制反转Inversion of Control DI和IoC几乎都是成对出现的,我们在理解依赖注入之前首先要弄明白什么是IoC,也就是控制反转,体现的就是控制权的转移,即控制权原来在A中,现在需要B ...
- 使用three.js实现炫酷的酸性风格3D页面
背景 近期学习了 WebGL 和 Three.js 的一些基础知识,于是想结合最近流行的酸性设计风格,装饰一下个人主页,同时总结一些学到的知识.本文内容主要介绍,通过使用 React + three. ...
- Winform 窗体自适应
前言 在使用 Winform 开发过程中,经常发些因为显示器分辨率.窗体大小改变,控件却不能自适应变化,几经查找资料,和大佬的代码.经过细小修改,终于可以让窗体在外界影响下,窗体内背景图片.控件都会自 ...