当前位置: 首页 > news >正文

P3957 [NOIP 2017 普及组] 跳房子

题目描述

给出 \(n\) 个点的坐标 \(a_i\) 和权值 \(s_i\),每次向右移动正距离 \(p\),满足 \(d-x \le p \le d+x\) 且落在给定的点上,求使经过点值的最大和不小于 \(k\) 的最小 \(x\)

思路

step1-二分答案

这道题我们要求的是最小的 \(x\),可显然我们无法将 \(x\) 设计到状态中去,然而,给定 \(x\) 求点值和的最大值,这一类问题是可以实现的。

所以,我们就可以以二分答案的方式列举出 \(x\) 的值,然后带入固定的 \(x\) 值求出最大的点值和 \(sum\),判断若 \(sum \ge k\) 则查找左区间,否则查找右区间,可以在 \(O(\log n)\) 的时间复杂度内解决,十分可以接受。

还有要注意每次我们进行二分时都要将用过的元素初始化一遍。

step2-动态规划

给定了 \(x\),怎么样求最大的点值和呢?我们可以使用动态规划解决问题,令 \(f_i\) 表示走到第 \(i\) 个点最大的点值和,其值就等于最大满足条件的 \(f_j\) 加上自己的权值,据此我们不难列出线性状态转移方程。

\[f_i= \max_{0 \le j \le i-1,d-x \le a_i-a_j \le d+x} f_j+s_i \]

实现也很容易,二重循环即可,因为有负数所以我们答案要取所有 \(f_i\) 的最大值,下列即实现代码。

bool check(int x)
{ll ans=-1e14;for(int i=1;i<=n;i++){for(int j=0;j<=i-1;j++){if(a[i]-a[j]<=d+x&&a[i]-a[j]>=d-x)//满足距离限制{f[i]=max(f[i],f[j]+s[i]);//转移}}ans=max(ans,f[i]);}return ans>=k; 
}

时间复杂度 \(O(n^2)\),加上二分查找总复杂度 \(O(n^2\log n)\),十分不能接受,期望得分50pts,考虑优化。

step3-单调队列优化

根据题目,我们可以知道 \(a_i\) 单调递增,所以对于决策点的选择就必然满足决策单调性,也就是说点 \(i\) 所的转移点一定是和 \(i-1\) 相同或在其之后的。那么,我们思考当一个点已经不满足 \(i\) 点的距离限制,那么对于 \(i\) 之后的点,也必然不满足后面所有点的限制条件,我们就可以用单调队列来实现这一题目了,还要注意因为 \(d-x \le p\) 的限制,我们不能直接插入点 \(i\) 到优先队列中,要枚举到位于 \(i\) 后面的点 \(k\) 时满足 \(d-x \le a_k-a_i\) 时再将 \(i\) 加入队列中。

这样一来,总时间复杂度就优化到了 \(O(n\log n)\),十分可以接受,此题完成。

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=5e5+10;
int n,d;
ll k;
int a[M],s[M];
ll f[M];
int l=0,r=1e9,mid;
bool check(int x)
{deque<int> q;ll ans=-1e14;int j=0;for(int i=1;i<=n;i++){while(a[i]-a[j]>=d-x&&j<=i-1){while(!q.empty()&&f[j]>=f[q.back()]) q.pop_back();q.push_back(j);j++;}while(!q.empty()&&a[i]-a[q.front()]>d+x) q.pop_front();if(!q.empty()) f[i]=f[q.front()]+s[i];ans=max(ans,f[i]);}return ans>=k; 
}
int main()
{int flag=0;scanf("%d%d%lld",&n,&d,&k);for(int i=1;i<=n;i++){scanf("%d%d",&a[i],&s[i]);}while(l<=r){for(int i=1;i<=n+1;i++) f[i]=-1e14;f[0]=0;mid=(l+r)>>1;if(check(mid)) flag=1,r=mid-1;else l=mid+1;}if(!flag) printf("-1\n");else printf("%d\n",l);return 0;
}
http://www.wxhsa.cn/company.asp?id=3444

相关文章:

  • C++中常用的STL容器
  • 我的数据科学探索之旅:从兴趣到公考与学习计划
  • MySQL 核心记录解析:从配置到存储的 “说明书 + 记录仪” 系统
  • JavaScript Array 对象
  • 代码规范
  • mac远程连接windows
  • 子类不依赖泛型,重写父类方法,通过强制类型转换父类方法参数出现的问题。——— 一个例子引发的思考
  • WebStorm代码一键美化
  • 3分钟搞定Vue组件库
  • Golang中设置HTTP请求代理的策略
  • [开源免费] iGTTS(Gemini TTS) 文本转语音(TTS)的命令行工具。
  • 结合Spring和MyBatis实现DAO层操作综述
  • 202205_CHIMA_follow
  • Lua脚本协助Redis分布式锁实现命令的原子性
  • 快读快写 学习笔记
  • Ubuntu 安装 CLion
  • AI编程实战
  • 25/9/13(补)
  • 面向对象编程(OOP)的原则
  • 【龙智Atlassian插件】Confluence周报插件上线AI智能总结,一键生成专业报告 - 实践
  • 数字化(管理)系统的工具化思考
  • 详细介绍:传统神经网络实现-----手写数字识别(MNIST)项目
  • C#语言中使用using关键字
  • 中育新版本OSS Token获取API分析
  • 25/9/12(补,上一篇是9/11的)
  • 动态编译 vs. 静态编译,容器时代那个更有优势?
  • 实用指南:操作系统类型全解析:从批处理到嵌入式
  • 【C++ 类和对象・高阶深化(下)】再探构造函数(含初始化列表),吃透 static 成员、友元、内部类及对象拷贝编译器优化 - 指南
  • VSCode 运行 C/C++ 程序
  • 3 字节