NOIP 2012 洛谷P1081 开车旅行
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 开车旅行的更多相关文章
- 洛谷 P1081 开车旅行(70)
P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...
- [NOIP2012] 提高组 洛谷P1081 开车旅行
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- 洛谷 P1081 开车旅行 —— 倍增
题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...
- 2018.11.04 洛谷P1081 开车旅行(倍增)
传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...
- 洛谷P1081 开车旅行(倍增)
题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...
- 洛谷P1081 开车旅行70分
https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...
- 洛谷 P1081 开车旅行【双向链表+倍增】
倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...
- 洛谷P1081 开车旅行
题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...
- 洛谷P1081——开车旅行
传送门:QAQQAQ 题意注意点: 1.是从前往后走,不能回头 2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久) 3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海 ...
随机推荐
- java list根据id获取子节点
工作中因业务需求,将数据库中的树状结构的数据根据父节点获取所有的子节点 实现思路 1.获取整个数据的list集合数据 2.将数据分组,java8 list有groupby分组,java8之前的自己遍历 ...
- 使用Photon引擎进行unity网络游戏开发(四)——Photon引擎实现网络游戏逻辑
使用Photon引擎进行unity网络游戏开发(四)--Photon引擎实现网络游戏逻辑 Photon PUN Unity 网络游戏开发 网络游戏逻辑处理与MasterClient 网络游戏逻辑处理: ...
- java学习笔记-01.对象入门
1.面向对象编程简称是OOP. 2.继承是通过 extends关键字实现的,接口是通过implements关键字实现的. 3.public:意味着后续的定义任何人均可使用. private:意味着除了 ...
- arcgis--arcmap导出点的X,Y坐标
arcmap操作的
- mysql innodb myisam 比较
InnoDB: 支持事务处理等 不加锁读取 支持外键 支持行锁 不支持FULLTEXT类型的索引 不保存表的具体行数,扫描表来计算有多少行 DELETE 表时,是一行一行的删除 InnoDB 把数据和 ...
- Nginx 使用札记
nginx是什么? nginx是俄罗斯人 Igor Sysoev为俄罗斯访问量第二的Rambler.ru站点开发的一个十分轻量级的HTTP服务器.它是一个高性能的HTTP和反向代理服务器,同时也可以作 ...
- 基础系列(6)—— C#类和对象
一.类介绍 类(class)是C#类型中最基础的类型.类是一个数据结构,将状态(字段)和行为(方法和其他函数成员)组合在一个单元中.类提供了用于动态创建类实例的定义,也就是对象(objec ...
- 项目Beta冲刺(团队)第一天
1.今天解决的进度 成员 进度 陈家权 回复界面设计,由于成员变动加上和其他成员距离较远,服务器404 赖晓连 改进Alpha版本页面没能及时更新的问题 雷晶 获取提问问题时间更新到数据库 林巧娜 今 ...
- CodeForces 57C Array 组合计数+逆元
题目链接: http://codeforces.com/problemset/problem/57/C 题意: 给你一个数n,表示有n个数的序列,每个数范围为[1,n],叫你求所有非降和非升序列的个数 ...
- MySQL 忘记root密码怎么办
前言:记住如果忘记root密码,在启动MySQL的时候,跳过查询授权表就ok了. 对于RedHat 6 而言 (1)启动mysqld 进程时,为其使用:--skip-grant-tables --sk ...