P1081 [NOIP2012]开车旅行[倍增]
P1081 开车旅行 题面较为啰嗦。大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点;花费为此差绝对值;若干询问从规定点向后最多花费$X$,且以移动方式A开始每走一次切换一次方式。求以A、B方式各花费多少。
不看题解切紫题一遍过了,兴奋~然而连想带写花了四小时左右,真要在noip考场上怕不是要凉。。。我太菜了QwQ
先看第一问,找比值最小点,实际上就是拆成$N$个询问,扔到第二问的询问里面做掉的说。所以主要看对于询问点怎么向后找终止点。可以猜出应该是$O(\log N)$一次询问,所以就要求高效的跳法。
考虑A若干次之后走到后面一个点,从这个点继续走,这样一个状态,很多询问都可能经历。所以对于一个点,希望预处理出以他为起点有关的信息。
维护从他开始的终点?显然不行。
若最远点$T_0$,可能当下到这起点已花了一些代价,由于代价制限导致走不到最远,大概能走到$T_1 < T_0$。也就是说,$S\sim T_1$这一段是我可以走过的,$T_1$之后都到不了。
所以可以根据实际情况二分查找最远点。实现起来,就是个倍增,到目标点要走$k$次,总是可以拆成走二的指数幂次叠加,枚举当前走的$2^i$次,可行就跳,不可行就呆原地。
这个是处理询问的方法。所以瓶颈就在于如何预处理倍增数组。坑死我了。
设计状态$fa[i][j],fb[i][j],to[i][j]$表示从$i$点出发,走$2^j$次,A、B各自花费,以及讫点。
对于底层$to[i][0]$,只采用A方式移动,找出后面次小代价即可。单独处理。
对于次底层$f[i][1]$,开始用AB轮流交替方式移动,所以在底层要顺便处理以B方式移动一次的相关信息,在这一层与A合并。
之后,由于每个状态都是走偶数次的,涉及转移状态都是以A开始的,比如我移动4次,由前2次和后2次拼接,这两段都是以A开始的。所以直接合并即可。
提一下最底层找相邻点的几种方法:
- 每个点后面离他最近的。。前驱后继?平衡树?考虑用set来替代。找出大于他的两个,小于他的两个(没有则设为0),排一下序处理出来
- set找4个点同上,然后。。分类讨论。。我的弱智方法。。。。qwq
- 双向链表。可以将数组排序,将其用数组模拟成链表,之后,和每个点相邻的,虽然不一定是原来数组中他后面的元素,但是对于原数组1号,他在排序数组中相邻的肯定是前驱后继。找出之后将之从链表中删除,再考虑原数组的2号点,这时就不存在1号点的干扰了,后面同理。
常数稍大,但不影响能过,反正都是$O((N+M)\log N)$的。相关细节注意一下即可,如超出1e9提前特判掉等等。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define dis first
#define pos second
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
namespace io{
const int SIZE = ( << ) + ;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - , c, qu[]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush (){fwrite (obuf, , oS - obuf, stdout);oS = obuf;}
inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
template <class I>
inline void read(I &x) {for (f = , c = gc(); c < '' || c > ''; c = gc()) if (c == '-') f = -;
for (x = ; c <= '' && c >= ''; c = gc()) x = x * + (c & ); x *= f;}
template <class I>
inline void print (I x){
if (!x) putc (''); if (x < ) putc ('-'), x = -x;while(x) qu[++ qr] = x % + '', x /= ;while (qr) putc (qu[qr--]);}
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::read;
using io::putc;
using io::print;
const int N=+,INF=0x3f3f3f3f;
set<pii> s;
int h[N],fa[N][],fb[N][],to[N][],to2[N],disb[N];
int n,Q,T,m; inline void preprocess_the_bottom(){
set<pii>::iterator up,down;
int d0,d1,d2,d3,p0,p1,p2,p3;
m=__lg(n);
fa[n][]=fb[n][]=disb[n]=;to[n][]=to2[n]=n+;s.insert(make_pair(h[n],n));
for(register int i=n-;i;--i){
down=up=s.lower_bound(make_pair(h[i],));
d0=d1=d2=d3=,p0=p1=p2=p3=n+;
if(down!=s.begin())--down,d0=h[i]-(*down).dis,d0>1e9?(d0=):(p0=(*down).pos);//下侧第一
if(down!=s.begin())--down,d2=h[i]-(*down).dis,d2>1e9?(d2=):(p2=(*down).pos);//下侧第二
if(up!=s.end())d1=(*up).dis-h[i],d1>1e9?(d1=):(p1=(*up).pos);//上侧第一
if(up!=s.end()&&++up!=s.end())d3=(*up).dis-h[i],d3>1e9?(d3=):(p3=(*up).pos);//上侧第二
if(d0){
if(d1){//两侧都有
if(d1<d0){
disb[i]=d1,to2[i]=p1;
if(d3&&d3<d0)fa[i][]=d3,to[i][]=p3;//上侧第二为次近
else fa[i][]=d0,to[i][]=p0;//下侧第一为次近
}
else{
disb[i]=d0,to2[i]=p0;
if(d2&&d2<=d1)fa[i][]=d2,to[i][]=p2;//下侧第二为次近
else fa[i][]=d1,to[i][]=p1;//上侧第一为次近
}
}
else{//只有下侧
disb[i]=d0,to2[i]=p0;
fa[i][]=d2,to[i][]=p2;
}
}
else disb[i]=d1,to2[i]=p1,fa[i][]=d3,to[i][]=p3;//只有上侧或者两侧都没有
// dbg(i);_dbg(disb[i],to2[i]);_dbg(fa[i][0],to[i][0]);
s.insert(make_pair(h[i],i));
}
to2[n+]=n+;for(register int i=;i<=m;++i)to[n+][i]=n+;
} inline void preprocess(){
for(register int i=;i<=n;++i)fa[i][]=fa[i][],fb[i][]=disb[to[i][]],to[i][]=to2[to[i][]];
for(register int i=;i<=m;++i){
for(register int j=;j<=n;++j){
fa[j][i]=fa[j][i-]+fa[to[j][i-]][i-],fb[j][i]=fb[j][i-]+fb[to[j][i-]][i-];to[j][i]=to[to[j][i-]][i-];
fa[j][i]+0ll+fb[j][i]>1e9?(fa[j][i]=,fb[j][i]=,to[j][i]=n+):;
}
}
}
int xa,xb;
inline void Query(int x,int tot){
xa=xb=;
for(register int i=m;~i;--i)if(to[x][i]<=n&&fa[x][i]+fb[x][i]<=tot)tot-=fa[x][i]+fb[x][i],xa+=fa[x][i],xb+=fb[x][i],x=to[x][i];
}
int x,tot,p,q,ans;
int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
read(n);for(register int i=;i<=n;++i)read(h[i]);
preprocess_the_bottom();preprocess();
read(Q);Query(,Q);p=xa,q=xb,ans=;
for(register int i=;i<=n;++i){
Query(i,Q);
if(!xb){if(!q)if(h[ans]<h[i])ans=i;continue;}
if(xa*1ll*q<xb*1ll*p)p=xa,q=xb,ans=i;
else if(xa*1ll*q==xb*1ll*p)if(h[ans]<h[i])ans=i;
}
print(ans);read(T);putc('\n');
for(register int i=;i<=T;++i){
read(x),read(tot);Query(x,tot);
print(xa),putc(' '),print(xb),putc('\n');
}
return ;
}
P1081 [NOIP2012]开车旅行[倍增]的更多相关文章
- 洛谷1081 (NOIp2012) 开车旅行——倍增预处理
题目:https://www.luogu.org/problemnew/show/P1081 预处理从每个点开始a能走多少.b能走多少.可以像dp一样从后往前推. 但有X的限制.所以该数组可以变成倍增 ...
- Luogu1081 NOIP2012 开车旅行 倍增
题目传送门 为什么NOIP的题目都这么长qwq 话说2012的D1T3和D2T3都是大火题啊qwq 预处理神题 对于这种跳跳跳的题目考虑使用倍增优化枚举.先预处理某个点之后距离最小和次小的城市,然后倍 ...
- Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)
1264. [NOIP2012] 开车旅行 ★★☆ 输入文件:drive.in 输出文件:drive.out 简单对比时间限制:2 s 内存限制:128 MB [题目描述] 小A 和小 ...
- 【vijos1780】【NOIP2012】开车旅行 倍增
题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...
- NOIP2012开车旅行 【倍增】
题目 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城 ...
- 洛谷 P1081 开车旅行 —— 倍增
题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...
- P1081 开车旅行[倍增](毒瘤题)
其实就是个大模拟. 首先,根据题意,小A和小B从任意一个城市开始走,无论\(X\)如何,其路径是一定唯一的. 显然对于两问都可以想出一个\(O(n^2)\)的暴力,即直接一步一步地向右走. 首先,我们 ...
- $Noip2012\ Luogu1081$ 开车旅行 倍增优化$ DP$
Luogu Description Sol 1.发现对于每个城市,小A和小B的选择是固定的,可以预处理出来,分别记为ga[],gb[] 2.并且,只要知道了出发城市和出发天数,那么当前城市和小A,小B ...
- luogu1081 [NOIp2012]开车旅行 (STL::multiset+倍增)
先用不管什么方法求出来从每个点出发,A走到哪.B走到哪(我写了一个很沙雕的STL) 然后把每个点拆成两个点,分别表示A从这里出发和B从这里出发,然后连边是要A连到B.B连到A.边长就是这次走的路径长度 ...
随机推荐
- 串的应用与kmp算法讲解--学习笔记
串的应用与kmp算法讲解 1. 写作目的 平时学习总结的学习笔记,方便自己理解加深印象.同时希望可以帮到正在学习这方面知识的同学,可以相互学习.新手上路请多关照,如果问题还请不吝赐教. 2. 串的逻辑 ...
- 【ABAP系列】SAP Smartforms 设置纸张打印格式
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP Smartforms 设 ...
- 防火墙之iptables
Netfilter/Iptables(以下简称Iptables)是unix/linux自带的一款优秀且开放源代码的完全自由的基于包过滤的防火墙工具,它的功能十分强大,使用非常灵活,可以对流入和流出服务 ...
- Leetcode #9 Easy <Palindrome Number>
题目如图,下面是我的解决方法: class Solution { public boolean isPalindrome(int x) { if(x < 0) //由题意可知,小于0的数不可能为 ...
- 【Python开发】Python中的class继承
继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子进程继承了父进程的所有公有实例变量和方法.继承实现了代码的重用.重用已经存在的数据和行为,减少代码的重新编写,python在类名后 ...
- C++学习笔记-C++与C语言的一些区别
本文主要是整理一些C++与C的一些小的区别,也就是在使用C与C++时候需要注意的一些问题,C++是以C语言为基础的,并且完全兼容C语言的特性 注释 C语言的注释形式为 /* 注释内容 */ 而C++提 ...
- Emgu 学习之HelloWorld
安装和配置 系统Win10,VS2013,下载Emgu安装包libemgucv-windesktop-3.4.3.3016 安装到了E:\OpenCV\emgucv-windesktop 3.4.3. ...
- 接口自动化框架 - httprunner
自己曾经写过一个接口自动化的框架,并做了一版本的优化,一直觉得做的还不错,且没依赖现有的框架. 最近因为一些工作的原因,开始又思考之前写的框架的一些缺点及如何优化,所以找到比较有名的httprunne ...
- java多线程的优先性问题
多线程的优先级问题 重点:理解线程优先级的继承性.规则性.随机性 线程的优先级 在操作系统中,线程可以划分优先级,.尽可能多的给优先级高的线程分配更多的CPU资源. 线程的优先级分为1~10,有三个预 ...
- Kick Start 2019 Round A Contention
$\DeclareMathOperator*{\argmax}{arg\,max}$ 题目链接 题目大意 一排 $N$ 个座位,从左到右编号 $1$ 到 $N$ . 有 $Q$ 个预定座位的请求,第 ...