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.边长就是这次走的路径长度 ...
随机推荐
- 【MM系列】SAP S/4 HANA BP创建客户/供应商的一点想法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP S/4 HANA BP创建客 ...
- HTTP及WEB框架简述
HTTP介绍 Hyper Text Transfer Protocol,超文本传输书协议,是万维网数据通信的基础,规定了请求和响应标准. HTTP工作原理 HTTP 请求以及响应的步骤 客户端连接到W ...
- webdriervAPI(元素等待)
from selenium import webdriver from selenium.common.exceptions import NoSuchElementException driv ...
- 【并行计算-CUDA开发】Windows下opencl环境配置
首先声明我这篇主要是根据下面网站的介绍, 加以修改和详细描述,一步一步在我自己的电脑上实现的, http://www.cmnsoft.com/wordpress/?tag=opencl&pag ...
- Web Components的概念和用法
参考链接:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
- java8 stream多字段排序
注:转载请注明出处!!!!!!! 很多情况下sql不好解决的多表查询,临时表分组,排序,尽量用java8新特性stream进行处理 使用java8新特性,下面先来点基础的 List<类> ...
- [python] 在指定目录下找文件
import os # 查找当前目录下所有包含关键字的文件 def findFile(path, filekw): return[os.path.join(path,x) for x in os.li ...
- PTA(Advanced Level)1036.Boys vs Girls
This time you are asked to tell the difference between the lowest grade of all the male students and ...
- 【0.2】【MySQL】常用监控指标及监控方法(转)
[MySQL]常用监控指标及监控方法 转自:https://www.cnblogs.com/wwcom123/p/10759494.html 对之前生产中使用过的MySQL数据库监控指标做个小结. ...
- springboot2.X版本得@Transactional注解事务不回滚不起作用
参考文章 https://my.oschina.net/happyBKs/blog/1624482 https://blog.csdn.net/u011410529/article/detail ...