Description:

就是两个人开车,只能向东开。向东有n个城市,城市之间的距离为他们的高度差。A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市。如果车子开到底了或者车子开的路程已经超过了限制X就停。

问你从一个点出发,最后A行驶的里程数和B行驶的里程数。

倍增的妙用,这道题改变了我对NOIP的看法。让我对着书看了好久才看懂

不过70分还是好拿的,就是预处理然后对每个询问$O(n)$ 模拟一遍。复杂度$O(nlog_{2}n+nm)$

怎么预处理?就是找到一个城市$i$后离他最近的城市和次近的城市,分别为$gb[i]$,$ga[i]$,用平衡树(set)或者链表或者权值线段树实现

满分在70分的基础上,倍增预处理,然后$O(log_{2}n)$回答每个询问

对于第一个询问,枚举起点即可。

接下来, $dp[i][j][k]$表示$k$在$j$点出发,共开$2^i$天的车到达的城市,1表示A,2表示B。

$sta[i][j][k]$表示$k$在$j$点出发,共开$2^i$天的车A所行驶的路程,$stb[i][j][k]$表示$k$在$j$点出发,共开$2^i$天的车B所行驶的路程。

边界和初值:$dp[0][j][0]=ga[j]$,$dp[0][j][1]=gb[j]$,$sta[0][j][0]=dist(j,ga[j])$,$stb[0][j][1]=dist(j,gb[j])$ 其他都为0

转移看代码,特别注意的是因为$i=1$时,两人是换着开的,所以转移的时候k要去个反。而$i>1$的话,$2^i$天和$2^{i-1}$时开车的人是相同的故不用取反

其他对着状态就能理解了把,就不写注释了。

 /*代码修改自李煜东霸霸,变量名是按照书上说法开的*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + ;
#define ll long long
ll sta[][N][], stb[][N][], ansA, ansB, la, lb;
int dp[][N][], n, m, ga[N], gb[N], h[N], i, t, ans;
struct node{ int x, y;} ;
set<node> s;
set<node>::iterator it,lt,rt;
int dist(int x, int y){ return abs(h[x] - h[y]); }
bool cmp(int x, int y){ return dist(x, i) == dist(y, i) ? h[x] < h[y] : dist(x, i) < dist(y, i); }
bool operator < (node a, node b){ return a.y < b.y; }
void solve(int s, int X){
la = lb = ; int k = ;
for(int j = t; j >= ; j--)
if(dp[j][s][k] && sta[j][s][k] + stb[j][s][k] <= X){
X -= (sta[j][s][k] + stb[j][s][k]);
la += sta[j][s][k], lb += stb[j][s][k];
if(j == ) k ^= ;
s = dp[j][s][k];
}
}
int main(){
scanf("%d", &n);
for(int i = ; i <= n; i++) scanf("%d", &h[i]);
for(i = n; i >= ; i--){
node tmp; tmp.x = i, tmp.y = h[i];
int temp[];
s.insert(tmp); it = s.find(tmp);
lt = it, rt = it, m = ;
if(lt != s.begin()) lt--, temp[++m] = lt -> x;
if(lt != s.begin()) lt--, temp[++m] = lt -> x;
if(rt++, rt != s.end()){
temp[++m] = rt -> x;
if(rt++, rt != s.end()) temp[++m] = rt -> x;
}
sort(temp + , temp + m + , cmp);
if(m) gb[i] = temp[];
if(m > ) ga[i] = temp[];
}
t = log(n * 1.0) / log(2.0);
for(i = ; i <= n; i++){
if(ga[i]) dp[][i][] = ga[i], sta[][i][] = dist(ga[i], i), stb[][i][] = ;
if(gb[i]) dp[][i][] = gb[i], stb[][i][] = dist(gb[i], i), sta[][i][] = ;
}
for(i = ; i <= t; i++)
for(int j = ; j <= n; j++)
for(int k = ; k < ; k++){
int l;
if(i == ) l = k ^ ; else l = k;
if(dp[i - ][j][k]) dp[i][j][k] = dp[i - ][dp[i - ][j][k]][l];
if(dp[i][j][k]){
sta[i][j][k] = sta[i - ][j][k] + sta[i - ][dp[i - ][j][k]][l];
stb[i][j][k] = stb[i - ][j][k] + stb[i - ][dp[i - ][j][k]][l];
}
}
int X0;
scanf("%d", &X0); ansA = , ansB = ;
for(i = ; i <= n; i++){
solve(i, X0);
if(!lb) la = ;
if(la * ansB < lb * ansA || (la * ansB == lb * ansA && h[i] > h[ans]))
ansA = la, ansB = lb, ans = i;
}
printf("%d\n", ans);
scanf("%d", &m);
int x, y;
while(m--){
scanf("%d%d", &x, &y);
solve(x, y);
printf("%lld %lld\n", la, lb);
}
return ;
}

倍增优化DP就是一个划分状态+状态拼凑的过程

NOIP 2012 洛谷P1081 开车旅行的更多相关文章

  1. 洛谷 P1081 开车旅行(70)

    P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...

  2. [NOIP2012] 提高组 洛谷P1081 开车旅行

    题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...

  3. 洛谷 P1081 开车旅行 —— 倍增

    题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...

  4. 2018.11.04 洛谷P1081 开车旅行(倍增)

    传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...

  5. 洛谷P1081 开车旅行(倍增)

    题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...

  6. 洛谷P1081 开车旅行70分

    https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...

  7. 洛谷 P1081 开车旅行【双向链表+倍增】

    倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...

  8. 洛谷P1081 开车旅行

    题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...

  9. 洛谷P1081——开车旅行

    传送门:QAQQAQ 题意注意点: 1.是从前往后走,不能回头 2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久) 3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海 ...

随机推荐

  1. [转]操作系统Unix、Windows、Mac OS、Linux的故事

    [写得很江湖气,可惜找不到原作者了] 文章转自:http://blog.csdn.net/wenmingchan/article/details/49925379 http://www.jb51.ne ...

  2. 韦大仙--LoadRunner压力测试:详细操作流程

    一. 录制脚本 1.安装完毕后,创建脚本: 点击OK之后,会弹出网址,之后创建Action,每进一个页面添加一个Action,录制结束后,终止录制. 二. 修改脚本 1.脚本参数化 将登录的用户名密码 ...

  3. 《图解 HTTP 》阅读 —— 第二章

    第2章 简单的http协议 http 协议用于客户端和服务器端的通信. 请求访问文本或图像等资源的一端称为客户端,提供资源响应的一端称为服务器端. 请求报文: 响应报文: 为了能够处理大量的事务,ht ...

  4. 梯度下降算法以及其Python实现

    一.梯度下降算法理论知识 我们给出一组房子面积,卧室数目以及对应房价数据,如何从数据中找到房价y与面积x1和卧室数目x2的关系?   为了实现监督学习,我们选择采用自变量x1.x2的线性函数来评估因变 ...

  5. [leetcode-915-Partition Array into Disjoint Intervals]

    Given an array A, partition it into two (contiguous) subarrays left and right so that: Every element ...

  6. c# 修改exe.config文件并且及时更新

    1.config文件地址:AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 注意:如果是在调试程序中运行,此地址指代的是vhost. ...

  7. Win10系统自带输入法的人机交互设计

    过了寒假回校以后,我的电脑重装了系统,为了提升系统运行的速度,自己装了一个内存条同时对硬盘进行了重新的分区,对电脑内的文件也进行了重新的整理,电脑的运行速度提高了很多.老多同学都说win10系统好用, ...

  8. P4语法(4)Control block

    Control block Control block之中用于放置设计好的Table和Action. 可以把control block认为是pipeline的一个模板,之前用的v1model中就是in ...

  9. Alpha冲刺——第八天

    Alpha第八天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  10. vs2015关于_CRT_SECURE_NO_WARNINGS警告说明

    vs2015关于_CRT_SECURE_NO_WARNINGS警告说明 在VS中调用 strcpy.strcat 等函数时会提示 _CRT_SECURE_NO_WARNINGS 警告,原因是这些函数不 ...