题面

传送门

分析

显然答案有单调性,可以二分答案,设当前二分值为g,根据题意我们可以求出跳跃长度的范围[l,r]

考虑DP

子状态: dp[i]表示跳到第i个点时的最大和

状态转移方程 \(dp[i]=max(dp[i],dp[j]+a[i]) (j \in [1,n),x[i]-x[j] \in [l,r])\)

初始值:dp[0]=0 (把起点看成第0号点,权值和坐标都为0)

直接转移的时间复杂度是\(O(n^2)\)

由于此题数据水,\(O(n^2logn)\)可以卡过

(相信热爱学习,不屑于打暴力的你一定会继续往下看的)

观察状态转移方程,发现满足条件的j一定在某个区间内,且区间在不断移动,类似“滑动窗口问题”,可建立一个单调队列

另外,j存在决策单调性,即i增加时,j一定也不断增加,不会再减小(例如对于i=1时我们求出满足条件的最大j,i=2时满足条件的j一定比i=1时的j更大)

因此,每次循环时j不必重置成0,这样可显著减少时间

然后维护单调队列

对于每个i,我们将满足条件(与i距离>l)的dp[j]不断加入队尾,并同时维护序列的单调性,保证队列从大到小递减,这样队头的答案一定最优

接着处理不合格的情况,即弹出队头与i距离>r的值

现在队头就是满足\(j \in [1,n),x[i]-x[j] \in [l,r]\)的最大dp[j]+a[i],因此用队头更新dp[i],i++,继续下一个循环

DP时间复杂度\(O(n)\)

总时间复杂度\(O(nlogn)\)

代码

暴力卡过:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500005
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int qread() {
int x=0,sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*sign;
}
int n,d;
int k;
int x[maxn];
int a[maxn];
long long dp[maxn];
int check(int g) {
int l0,r0;
memset(dp,-0x3f,sizeof(dp));
long long ans=dp[0];
if(g<d) {
l0=d-g;
r0=d+g;
} else {
l0=1;
r0=d+g;
}
dp[0]=0;
for(int i=1; i<=n; i++) {
for(int j=i-1; j>=0; j--) {
if(x[i]-x[j]<l0) continue;
if(x[i]-x[j]>r0) break;
if(dp[j]+a[i]>dp[i]) dp[i]=dp[j]+a[i];
if(dp[i]>=k) return 1; }
if(dp[i]>ans) ans=dp[i];
}
if(ans>=k) return 1;
else return 0;
} int main() {
n=qread();
d=qread();
k=qread();
for(int i=1; i<=n; i++) {
x[i]=qread();
a[i]=qread();
}
dp[0]=0;
x[0]=0;
int l=0,r=1005;
int mid;
int ans=-1;
int t;
while(l<=r) {
mid=(l+r)>>1;
if(check(mid)) {
ans=mid;
r=mid-1;
} else l=mid+1;
}
printf("%d\n",ans);
}
//Dedicated to Selina

单调队列:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500005
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int n,d;
int k;
int x[maxn];
int a[maxn];
long long dp[maxn];
struct node{
long long v;
int x;
node(){ }
node(long long val,int pos){
v=val;
x=pos;
}
};
struct deque{
int head,tail;
node Q[maxn];
node front(){
return Q[head];
}
node back(){
return Q[tail-1];
}
void push_back(node p){
Q[tail]=p;
tail++;
}
void pop_front(){
head++;
}
void pop_back(){
tail--;
}
bool empty(){
if(head<tail) return 0;
else return 1;
}
deque(){
head=tail=0;
}
void clear(){
head=tail=0;
}
}q;
int check(int g){
int l0,r0;
if(g<d) {
l0=d-g;
r0=d+g;
} else {
l0=1;
r0=d+g;
}
int j=0;
memset(dp,-0x3f,sizeof(dp));
q.clear();
dp[0]=0;
for(int i=1;i<=n;i++){
while(x[i]-x[j]>=l0){//由于j有决策单调性,不必清零
while(!q.empty()&&dp[j]>=q.back().v) q.pop_back();//保证序列单调递减
q.push_back(node(dp[j],x[j]));
j++;
}
while(!q.empty()&&x[i]-q.front().x>r0) q.pop_front();//排除不符合条件的情况
if(q.empty()) dp[i]=-INF;//如果队列为空,说明该点不能到达,直接设为-INF
else dp[i]=q.front().v+a[i];
if(dp[i]>=k) return 1;
}
return 0;
}
int main(){
scanf("%d %d %d",&n,&d,&k);
for(int i=1;i<=n;i++){
scanf("%d %d",&x[i],&a[i]);
}
x[0]=0;
int l=0,r=x[n];
int mid;
int ans=-1;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)){
ans=mid;
r=mid-1;
}else l=mid+1;
}
printf("%d\n",ans);
}
//Dedicated to Selina

luogu P3657 (NOIP2017) 跳房子(二分+DP+单调队列)的更多相关文章

  1. 洛谷 P3957 跳房子 —— 二分答案+单调队列优化DP

    题目:https://www.luogu.org/problemnew/show/P3957 先二分一个 g,然后判断: 由于转移的范围是一个区间,也就是滑动窗口,所以单调队列优化: 可以先令队尾为 ...

  2. [acmm week12]二分+dp+单调队列

    1004 抄作业         Time Limit: 1sec    Memory Limit:256MB Description Zfree虽然平时很爱学习,但是他迫于生活所迫(比如设计cpu实 ...

  3. bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】

    把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i- ...

  4. 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description ...

  5. [NOIP2017普及组]跳房子(二分,单调队列优化dp)

    [NOIP2017普及组]跳房子 题目描述 跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一. 跳房子的游戏规则如下: 在地面上确定一个起点,然后在起点右侧画 nn 个格子, ...

  6. [BZOJ 2500]幸福的道路 树形dp+单调队列+二分答案

    考试的时候打了个树链剖分,而且还审错题了,以为是每天找所有点的最长路,原来是每天起点的树上最长路径再搞事情.. 先用dfs处理出来每个节点以他为根的子树的最长链和次长链.(后面会用到) 然后用类似dp ...

  7. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)

    DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...

  8. DP+单调队列 codevs 1748 瑰丽华尔兹(还不是很懂具体的代码实现)

    codevs 1748 瑰丽华尔兹 2005年NOI全国竞赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题解       题目描述 Descripti ...

  9. BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列

    BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列 题意: 分析: 拆成链,二分答案,奇偶两个单调队列维护最大子段和,记录方案. 代码: #include <cstdio&g ...

随机推荐

  1. ASE Backend Alpha Sprint Review

    [Backend] Alpha Review展示博客 团队成员介绍:仅限于Alpha阶段有贡献的成员. 典型场景描述:描述并说明你们认为的产品面向的典型场景. 团队管理与协作:包括但不限于团队内部如何 ...

  2. Java REST Client API

    https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-supported-apis.htm ...

  3. 编译安装github上的kafka_exporter项目

    本文介绍的kafka_exporter是prometheus监控系统中针对kafka的一款监控插件,要使用这个监控插件,kafka的版本需要满足 0.10.1.0 及以上. 项目的github地址:h ...

  4. MongoDB的应用

    一.MongoDB后台管理 # ./mongo MongoDB shell version v3.4.2 connecting to: mongodb://127.0.0.1:27017 MongoD ...

  5. vue中怎么使用vuex

    做一个简单的vuex如何使用的介绍: 先安装: npm i vuex --save-dev 新建一个store文件夹, 在store文件夹中建一个index.js文件,在该文件中:         i ...

  6. (1)消灭初级程序员常用的多层if-else嵌套--------------【表驱动法】

    表驱动法 1.相信很多刚从事工作的程序员或一些初级程序员在写代码的时候会出现对一些逻辑判断写成多层if-else嵌套的经历,这种方式在一些简单的层次中运用起来确实可行,但对于一些大型项目逻辑判断比较多 ...

  7. 2019 上海网络赛 F Rhyme scheme (字典树DP)

    题目:https://nanti.jisuanke.com/t/41414 题意:求长度为n的第k个bell number  ,  就是第i位的选取范围在 1-(i-1)位的最大值 +1,第一位固定为 ...

  8. 字符串(一):char 数组

    字符串使用方法整理 系列: 字符串(一):char 数组 字符串(二):string 1. 声明 如下是一个例子(=> 表示表达式等价): char a[20] = "abcd&quo ...

  9. html、css、js分工,内核,html头,html表单

    html:内容css:样式js:交互 内核 浏览器控制台输入navigator.userAgent,回车显示出内核"Mozilla/5.0 (Windows NT 6.1; WOW64) A ...

  10. matplot在Mac下显示中文的方案

    使用matplotlib经常会出现中文显示异常的问题. 网上很多都讲需要下载中文字体包...偶然看到别人发的一种简单的解决放啊.Mac上本身就有支持中文的字体包啊.引入就好了 贴上代码 plt.rcP ...