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.边长就是这次走的路径长度 ...
随机推荐
- 关于ckeditor在IE下出现不兼容的问题
今天在用ckeditor时在ie下测试出现了不兼容问题,样式,字体等属性设置不了. 后来在html标签上方添加了: <!DOCTYPE html PUBLIC "-//W3C//DTD ...
- 【C/C++】assert()函数用法总结
assert()函数用法总结 assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义: #include <assert.h> ...
- Java架构师 成长之路 -- 跳出程序员陷阱(转载)
本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路. 如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序 ...
- Java程序员的职业发展道路 附:大型网站 -- 架构技能图谱(Java版)
职业发展道路基本有3条: 第一条路线(技术专精): 初级Java开发---中级--高级---项目主管--Java项目经理---网站架构师----资深专家 第二条路线(技术转产品):初级Java开发-- ...
- java中怎么调用python 脚本
调用方法: import java.io.BufferedReader; import java.io.InputStreamReader; public class PythonInvoke { p ...
- python 爬虫 urllib模块 反爬虫机制UA
方法: 使用urlencode函数 urllib.request.urlopen() import urllib.request import urllib.parse url = 'https:// ...
- Java中String连接性能的分析
总结:如果String的数量小于4(不含4),使用String.concat()来连接String,否则首先计算最终结果的长度,再用该长度来创建一个StringBuilder,最后使用这个String ...
- 菜鸟系列Fabric——Fabric 1.2 多机部署(3)
多机部署fabric kafka共识 1. 角色分配 主机1 主机 2 Org1 peer0 1 Org2 peer 0 1 Orderer 0 1 Orderer 2 kafka 0 1 kafka ...
- PTA(Basic Level)1036.跟奥巴马一起编程
美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014 年底,为庆祝"计算机科学教育周"正式启动,奥巴马编写了很简单的计算机 ...
- java-selenium三种等待方式
方式1: 线程等待:Thread.sleep(xxxx) 只要在case中加入sleep就会强制等待设置的时间后才会执行之后的命令,这种等待一般适用于调试脚本的时候. java代码 //等待3秒 Th ...