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 ...
随机推荐
- 255 day03_List、Set、数据结构、Collections
day03 [List.Set.数据结构.Collections] 主要内容 数据结构 List集合 Set集合 Collections 教学目标 [ ] 能够说出List集合特点 [ ] 能够说出常 ...
- git 要求密码的解决方法:【生成gitLab公钥】:以及如何配置GitLab中的SSH key
参考链接: https://www.cnblogs.com/yjlch1016/p/9692840.html https://blog.csdn.net/u011925641/article/deta ...
- 最小化安装centos7心得
在虚拟机里最小化安装了centos7,只有字符界面,发现网卡不通,解决方法: 调整网卡配置文件: cd /etc/sysconfig/network-scripts/ 有两个ifcfg文件,一个ifc ...
- C# 显示、隐藏窗口对应的任务栏
WPF中全屏窗口,会自动隐藏任务栏. 那非全屏窗口如何隐藏任务栏?甚至有没有一种场景,隐藏任务后自定义一套系统任务栏来显示? 以下会分阶段讲述一些概念 1. 主屏任务栏 任务栏,其实也是一个窗口,主屏 ...
- VUE自学日志02-应用与组件实例
准备好了吗? 我们刚才简单介绍了 Vue 核心最基本的功能--本教程的其余部分将更加详细地涵盖这些功能以及其它高阶功能,所以请务必读完整个教程! 应用 & 组件实例 创建一个应用实例创建一个应 ...
- Springboot在有锁的情况下如何正确使用事务
1. 概述 老话说的好:想要赚钱,就去看看有钱人有什么需求,因为有钱人钱多,所以赚的多. 言归正传,在Java项目的研发中,"锁"这个词并不陌生,最经典的使用场景是商品的超卖问题. ...
- Linux基础安全配置(centos7)
1.帐户口令的生存期不长于90天 sed -i.old 's#99999#90#g' /etc/login.defs egrep "90" /etc/login.defs 2.密码 ...
- WinForm 控件 DataGridView 常用操作
1.取消列自动生成 在窗体load事件里面设置表格dataGridView的AutoGenerateColumns为 false dataGridView.AutoGenerateColumns = ...
- linux启动redis命令
首先进入到/usr/local/bin目录下(因为你redis安装的目录绝大多数都在这里) root@xxxx:/usr/local/bin#:redis-server wangconfig/redi ...
- 题解 [AGC017C] Snuke and Spells
题目传送门 Description 有 \(n\) 个球排在一起,每个球有颜色 \(a_i\),若当前有 \(k\) 个球,则会将所有 \(a_i=k\) 的球删掉.有 \(m\) 次查询,每次将 \ ...