洛谷P3957 跳房子(Noip2017普及组 T4)
今天我们的考试就考到了这道题,在考场上就压根没有思路,我知道它是一道dp的题,但因为太弱还是写不出来。
下来评讲的时候知道了一些思路,是dp加上二分查找的方式,还能够用单调队列优化。
但看了网上的许多代码和博客都觉得不太明白单调队列的应用,看来真的还是太菜了。
单调队列掌握不熟练(其实什么也不知道了,虽然之前是讲过的)
那就换一种思路,不用单调队列,二分+dp其实就能搞出来。
怎么能看出这道题是二分的呢?其实因为可以分析数据看出,花费的数量是成单调递增的,满足二分是单调性的情况,所以我们可以用二分答案的形式。
主函数里我就用了一个二分答案
int main()
{
scanf("%lld%lld%lld",&n,&d,&k);
for(ll i=;i<=n;i++)
{
scanf("%lld%lld",&a[][i],&a[][i]);//输入距离和费用
}
ll l=;//从零开始
ll r=;//随便定的一个右端点值
ll mid;
while(l<=r)//二分答案模板
{
mid=(l+r)>>;
if(check(mid))
{
ans=mid;//最优解是mid
r=mid-;
}
else
{
l=mid+;
}
}
}
二分当然还少不了check函数
那么我们的dp也就包含在check函数当中
然后呢
从题中就可以读出改造后机器人可以行走的步数的最小值d-g以及最大值d+g,就大概有了一个范围;
那既然是dp,就应该使用状态转移
在这里其实又可以有两种转移的方式
1.从当前点开始像前面转移,就可已从前面找可以使它跳动的距离最大的值,并且这个值又在范围内
转移方程(最优值) f[当前点]=max(f[从当前点往前面找]+a[1][当前点](当前点的价值),f[当前点](已经保存的最优值));
当这个最优值比预期的k大于或等于时
就说明存在这样的一个修改值满足条件
之后就是二分答案的查找
代码如下
bool check(int x)
{
ll left=d-x;
if(d-x<)
{
left=;//默认的最小值为1,避免越界
}
ll right=d+x;
memset(f,-,sizeof(f));//初始化数组为一个特别小的数
f[]=;
for(ll i=;i<=n;i++)
{
for(ll j=i-;j>=;j--)//从当前点之前的开始找
{
if(a[][i]-a[][j]<left)//如果距离比最小的值都小,就忽略可以不修改
{
continue;
}
if(a[][i]-a[][j]>right)//如果最大的距离都满足不了,结束不用找
{
break;
}
f[i]=max(f[i],f[j]+a[][i]);//转移方程
if(f[i]>=k)//满足条件
{
return true;
}
}
}
return false;
}
2.从当前的格子向后转移,顺着找最优解
这样又怎么办呢?
相信大佬秒看就知道了
当前的点就是从0开始,在n之前的所有点
转移方程为f[后面的点]=max(f[后面的点](已经储存的最优解),f[当前点](当前最优解)+a[1][后面点]);
代码就在下面了
bool check(int x)
{
ll left=d-x;
if(d-x<)
{
left=;
}
ll right=d+x;
memset(f,-,sizeof(f));//初始化不用说
f[]=;/没有走时的最优解为0
for(ll i=;i<n;i++)//有没有等于号都无所谓了
{
for(ll j=i+;j<=n;j++)//从当前点后面的一个点开始,也可以就从i点来
{
if(a[][j]-a[][i]<left)
{
continue;
}
if(a[][j]-a[][i]>right)
{
break;
}
f[j]=max(f[j],f[i]+a[][j]);//转移方程向后面转移
if(f[j]>=k)
{
return true;
}
}
}
return false;
}
完整代码1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,d,k,ans;
ll a[][];
ll f[];
bool check(int x)
{
ll left=d-x;
if(d-x<)
{
left=;
}
ll right=d+x;
memset(f,-,sizeof(f));
f[]=;
for(ll i=;i<=n;i++)
{
for(ll j=i-;j>=;j--)
{
if(a[][i]-a[][j]<left)
{
continue;
}
if(a[][i]-a[][j]>right)
{
break;
}
f[i]=max(f[i],f[j]+a[][i]);
if(f[i]>=k)
{
return true;
}
}
}
return false;
}
int main()
{
scanf("%lld%lld%lld",&n,&d,&k);
for(ll i=;i<=n;i++)
{
scanf("%lld%lld",&a[][i],&a[][i]);
}
ll l=;
ll r=;
ll mid;
while(l<=r)
{
mid=(l+r)>>;
if(check(mid))
{
ans=mid;
r=mid-;
}
else
{
l=mid+;
}
}
printf("%lld",ans);
return ;
}
完整代码2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,d,k,ans;
ll a[][];
ll f[];
bool check(int x)
{
ll left=d-x;
if(d-x<)
{
left=;
}
ll right=d+x;
memset(f,-,sizeof(f));
f[]=;
for(ll i=;i<=n;i++)
{
for(ll j=i;j<=n;j++)
{
if(a[][j]-a[][i]<left)
{
continue;
}
if(a[][j]-a[][i]>right)
{
break;
}
f[j]=max(f[j],f[i]+a[][j]);//转移方程从前一个格子转移过来
if(f[j]>=k)
{
return true;
}
}
}
return false;
}
int main()
{
scanf("%lld%lld%lld",&n,&d,&k);
for(ll i=;i<=n;i++)
{
scanf("%lld%lld",&a[][i],&a[][i]);
}
ll l=;
ll r=;
ll mid;
while(l<=r)
{
mid=(l+r)>>;
if(check(mid))
{
ans=mid;
r=mid-;
}
else
{
l=mid+;
}
}
printf("%lld",ans);
return ;
}
好了,这道题算是比较明白了,没有任何优化,在洛谷上也是可以AC的
之后搞懂了单调队列优化,再回头来改的更完善
如果有不足之处,就请大佬来为本蒟蒻提出来
就是这样
洛谷P3957 跳房子(Noip2017普及组 T4)的更多相关文章
- 洛谷 P3957 跳房子 —— 二分答案+单调队列优化DP
题目:https://www.luogu.org/problemnew/show/P3957 先二分一个 g,然后判断: 由于转移的范围是一个区间,也就是滑动窗口,所以单调队列优化: 可以先令队尾为 ...
- 洛谷P3957 跳房子
普及组的题.....填坑来了. 当年的我一眼二分+DP,现在都佩服起自己来了...... 然后我们就写个二分,在check里面写单调队列优化DP即可. 然后就A了...... #include < ...
- 2018.09.26洛谷P3957 跳房子(二分+单调队列优化dp)
传送门 表示去年考普及组的时候失了智,现在看来并不是很难啊. 直接二分答案然后单调队列优化dp检验就行了. 注意入队和出队的条件. 代码: #include<bits/stdc++.h> ...
- 洛谷 P5662 纪念品 & [NOIP2019普及组] (dp,完全背包)
传送门 解题思路 本题首先要明白,在每一天时,最优策略是先进行操作2(卖),再进行操作1(买),才能是利益最大化. 本题很显然当只有两天时,是一个完全背包,就是把当日价钱当做体积,把明日价格和今日价格 ...
- 洛谷 P3957 跳房子
https://www.luogu.org/problemnew/show/P3957 错误记录:1.没开longlong 2. -inf不够小 #include<cstdio> #inc ...
- 洛谷P3957 跳房子 题解 二分答案/DP/RMQ
题目链接:https://www.luogu.org/problem/P3957 这道题目我用到了如下算法: 线段树求区间最大值: 二分答案: DP求每一次枚举答案g时是否能够找到 \(\ge k\) ...
- 洛谷 3959 宝藏 NOIP2017提高组Day2 T2
[题解] 状压DP. f[i]表示现在的点是否连接的状态是i. #include<cstdio> #include<cstring> #include<algorithm ...
- 题解 【洛谷P1035】[NOIP2002普及组]级数求和
[NOIP2002普及组]级数求和 这个题……用循环也是可以的,不过我写了两种循环的题解,供各位dalao参考!O(∩_∩)O谢谢! for循环版本: #include<bits/stdc++. ...
- 题解【洛谷P1046】[NOIP2005普及组] 陶陶摘苹果
[NOIP2005] 陶陶摘苹果 首先,我们用一个数组s[11]存储每个苹果的高度. 然后,用a表示陶陶的身高. 接着,用a+30与s[i]比较,大于则计数器加一. 最后,输出计数器的值即可. #in ...
随机推荐
- PHP中利用pcntl实现多进程(模拟多线程)实例(转)
windows不支持pcntl的多线程(非Unix类系统不支持此模块),pcntl在很久很久之前就听过了,但是一直没有尝试着真正要用它. 这不,遇到socket问题了,看socket,遇到pcntl了 ...
- Java开发笔记(十)一元运算符的技巧
前面讲到赋值运算符的时候,提到“x = x+7”可以被“x += 7”所取代,当然Java编程中给某个变量自加7并不常见,常见的是给某变量自加1,就像走台阶,一般都是一级一级台阶地走,犯不着一下子跳上 ...
- 如何清理Docker占用的磁盘空间?
摘要:用了 Docker,好处挺多的,但是有一个不大不小的问题,它会一不小心占用太多磁盘,这就意味着我们必须及时清理. 作为一个有信仰的技术公司,我们Fundebug的后台采用了酷炫的全 Docker ...
- Android开发,关于如何在应用间共享SharedPreference
开发一个应用,需要用到两个应用A和B之间共享数据的问题,这个数据是个单一的数据,所以就想用SharedPrefernce来进行保存. 使用网上的各种应用间的共享代码,B是读取A的数据,所以代码为: C ...
- asp.net core webapi/website+Azure DevOps+GitHub+Docker
asp.net core webapi/website+Azure DevOps+GitHub+Docker 新春开篇作,主要写一下关于asp.net core web/api 2.2 项目借助dev ...
- JIRA笔记(一):安装部署JIRA
(一) 说明 说明JIRA的安装及破解. 操作系统:WIN 10 数据库:Oracle 12C R2(这个版本的jira,atlassian建议的是 12C R1,不过R2也能用,其他版本不清 ...
- 数据库之redis篇(1)—— redis数据库安装,简单使用
简介 reids,由Salvatore Sanfilippo写的一个高性能的key-value数据库,并且它是非关系型数据库,也就是没有像mysql那样多表链接操作,并且它是是完全开源免费的,遵守BS ...
- 【Spring】application.xml文件配置
什么是Spring? Spring是分层的javaEE full-stack(一站式)轻量级开源框架. ---注解配置--针对SSM <?xml version="1.0" ...
- 从Excel中导入数据时,提示“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”的解决办法
注意,64位系统,用64位的补丁文件; https://www.cnblogs.com/A2008A/articles/2438962.html 操作系统:使用的是64位的Windows Server ...
- 常见设计模式 (python代码实现)
1.创建型模式 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对 ...