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. Django——test文件编写接口测试

    用自己建立的小网页来做接口测试,在Django的tests.py写下如下 test_login_page为用get方式登录login路径,根据回复验证是否查看到页面 test_login_action ...

  2. 自己动手做AI:Google AIY开发工具包解析

    2018年国际消费性电子展(CES)上,最明显的一个趋势是Amazon与Google的语音技术进驻战,如AmazonAlexa进驻到Acer笔电内,Google Assist进驻到KIA汽车内,其他如 ...

  3. zabbix_agentd-install.sh (脚本部署zabbix_agentd服务)

    原文发表于cu:2016-05-20 基于http://www.cnblogs.com/netonline/p/7406598.html(http://blog.chinaunix.net/uid-2 ...

  4. AWS/阿里/Azure,云厂商价格大PK

    以下选取热门型号Linux虚拟机,AWS和Azure的虚拟机配置包括本地SSD临时盘,阿里云虚拟机不带本地SSD临时盘,而且需要另配网卡带宽.以下价格为人民币含税(6%) 按使用量网站直接付费购买(O ...

  5. text-align与vertical-align属性的区别

    1.text-align属性设置元素在水平方向(x轴)的位置 text-align:left://文本居左 text-align:center://文本居中 text-align:right: //文 ...

  6. 关于0x80000000为什么等于-2147483648和负数在内存上储存的问题

    转载自大佬的博客https://blog.csdn.net/youyou362/article/details/72667951/ 1·先说明负数怎么储存 (1)十进制负数是以其补码储存在内存上. 验 ...

  7. OrderSys---Spring 计划(第一天)

    Sprint 计划会议: 目标: 1.了解需求分析书的内容 2.划分OrderSys的功能模块 3.开始制作原型 Sprint 3 Backlog细化: ID Name Est How to demo ...

  8. emmmmmm

    211606342杨艺勇 211606379王熙航 单元测试 对每一个代码块进行测试,返回测试结果并和预期结果进行比对 对源代码进行相应的重构,以适应测试代码的调用,且不影响源代码的正常运行 通过与构 ...

  9. tomcat开发环境配置

    1.环境配置教程 环境变量.安装版.配置版 2.编写启动tomcat的批处理文件 3.改变端口 4.虚拟目录

  10. hdu1010--Tempter of the Bone(迷宫)

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1010 Tempter of the Bone Time Limit: 2000/1000 MS (Jav ...