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 ...
随机推荐
- HCNP Routing&Switching之IS-IS路由聚合和认证
前文我们了解了IS-IS路由渗透和开销相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15302382.html:今天我们来聊一聊IS-IS路由聚合和认 ...
- 论文解读(BYOL)《Bootstrap Your Own Latent A New Approach to Self-Supervised Learning》
论文标题:Bootstrap Your Own Latent A New Approach to Self-Supervised Learning 论文方向:图像领域 论文来源:NIPS2020 论文 ...
- Java统计文件中字母个数
import java.text.DecimalFormat; import java.io.File; import java.io.FileReader; import java.io.Buffe ...
- cnblogs-theme-silence 主题设置简约风格
本文参考 更改博客皮肤 更改博客皮肤为Custom 页面定制CSS代码 勾选禁用模板默认CSS 导入复制该文件内容到代码框中 配置代码块复制功能 样式 和 右侧滑动条样式 /*复制功能添加按钮 beg ...
- 成本降低40%、资源利用率提高20%的 AI 应用产品云原生容器化之路
作者 郭云龙,腾讯云高级工程师,目前就职于 CSIG 云产品三部-AI 应用产品中心,现负责中心后台业务框架开发. 导语 为了满足 AI 能力在公有云 SaaS 场景下,服务和模型需要快速迭代交付的需 ...
- nuxt打包等注意事项
打包步骤: 1.首先执行 npm run build 2.将打包好的 .nuxt static nuxt.config.js package.json 这四个文件丢到服务器的某个文件夹中,在服务器上安 ...
- 织梦arclist文章标题字数太短
解决dedecms UTF-8首页文章标题显示字数太短的办法原因分析:因为UTF-8编码1个中文汉字占用的是3个字节,GBK占用的是2个字节,所以,原先$titlelen = AttDef($titl ...
- dede新增字段调用方法
各位在使用{dede:channel }标签的时候,难免会遇到因为现在字段不能满足业务需求,需要新增的情况(具体怎么新增字段自行百度). 但是新增的字段通过DEDE的标签是不能直接使用的,现在博主介绍 ...
- js屏蔽右键代码
<script type="text/javascript"> document.body.oncontextmenu=document.body.ondragstar ...
- 利用griddata进行二维插值
有时候会碰到这种情况: 实际问题可以抽象为 \(z = f(x, y)\) 的形式,而你只知道有限的点 \((x_i,y_i,z_i)\),你又需要局部的全数据,这时你就需要插值,一维的插值方法网上很 ...