题面

LOJ#6435. 「PKUSC2018」星际穿越

题解

**参考了 这位大佬的博客 **

这道题好恶心啊qwq~~

首先一定要认真阅读题目 !! 注意 \(l_i<r_i<x_i\) 这个条件 !!

所以它询问的就是向左走的最短路了 .

不难发现只有两种策略 , 要么一直向左走 ; 要么第一次向右走 , 然后一直向左走 .

并且到一个定点 \(x\) 的最短路长度 肯定是从右向左一段段递增的 .

 为什么呢 ? 不难发现 如果向右走两次 , 那么只有一次是一定有效的 , 另外一次的 \(l_i\) 一定不会小于这次 .

向左走的话 , 每次就记下沿途的 \(l_i\) 的最小值 , 用这个去转移走 \(j\) 次时 \(l\) 的最小值就行了 . ( \(70pts\) 见我 \(LOJ\) 提交吧qwq .)

然后这样暴力做的话就是 \(O(n^2)\) 的复杂度 显然不行 .

考虑优化 , 发现这个是一段段的 且 有连续性 , 有一个神奇的倍增可以快速实现这个功能 .

令 \(f_{i, j}\) 为 \([i, n]\) 所有点走 \(2^j\) 次能到达的最左端点 .

\[\displaystyle f_{i,j} = f_{f_{i,j-1},j-1}
\]

为什么要这样记呢 ? 因为这样可以同时统计第一次向右走可能产生的贡献 .

令 \(sum_{i,j}\) 为 \(i \to (i \sim f_{i,j})\) 中所有点走的步数之和 . 这个转移就很显然啦 .

\[sum_{i,j} = sum_{i,j-1}+sum_{{f_{i,j-1}},j-1} + (f_{i,j-1}-f_{f_{i,j-1},j-1})*2^{j-1}
\]

然后我们考虑走的时候算答案 . 因为我们一开始预处理只包括了可能向右走的情况 , 但直接第一步向左走的没有处理掉 .

此处我们单独处理第一步向左走的情况就行了 .

令 \(Calc(i, pos)\) 为 \(i \to [i, pos)\) 的所需步数之和 . 那么每次询问就能用差分来表示成 \(Calc(l,pos) - Calc(r + 1, pos)\) 了 .

然后倍增的时候类似于这样跳的 :

假设我们总共要经过的是 红色 那一段(其中 \(l_{pos}\) 已经跳完了) , 每次走的是 粉色 那一段 .

发现我们每次走的时候 , 要记下前面走了多少步数 , 然后给答案加上这一段的贡献 \(len \times tot\) .

最后有一小段多余的 蓝紫色 (因为每次 \(2^j\) 覆盖的是所有步数为这么多的 , 最后可能不满) 这段贡献就是 \(len \times (tot + 1)\) .

代码好像很短 ?

代码

  1. #include <bits/stdc++.h>
  2. #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
  3. #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
  4. #define Set(a, v) memset(a, v, sizeof(a))
  5. #define debug(a) cout << #a << ": " << a << endl
  6. using namespace std;
  7. inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
  8. inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
  9. inline int read() {
  10. int x = 0, fh = 1; char ch = getchar();
  11. for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
  12. for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
  13. return x * fh;
  14. }
  15. void File() {
  16. #ifdef zjp_shadow
  17. freopen ("6435.in", "r", stdin);
  18. freopen ("6435.out", "w", stdout);
  19. #endif
  20. }
  21. const int N = 3e5 + 1e3, inf = 0x3f3f3f3f;
  22. int L[N], n, f[N][21], sum[N][21], Log2[N];
  23. void Init() {
  24. f[n + 1][0] = inf;
  25. Fordown (i, n, 1)
  26. f[i][0] = min(f[i + 1][0], L[i]), sum[i][0] = i - f[i][0];
  27. For (j, 1, Log2[n]) For (i, 1, n) if (f[i][j - 1]) {
  28. f[i][j] = f[f[i][j - 1]][j - 1];
  29. sum[i][j] = sum[i][j - 1] + sum[f[i][j - 1]][j - 1] + ((f[i][j - 1] - f[i][j]) << (j - 1));
  30. }
  31. }
  32. inline int Calc(int qp, int pos) {
  33. if (L[pos] <= qp) return pos - qp;
  34. int res = pos - L[pos]; pos = L[pos]; int tot = 1;
  35. Fordown (i, Log2[pos], 0)
  36. if (f[pos][i] > qp) res += sum[pos][i] + (pos - f[pos][i]) * tot, pos = f[pos][i], tot += 1 << i;
  37. return res + (pos - qp) * (tot + 1);
  38. }
  39. int main () {
  40. File();
  41. n = read(); L[1] = 1; For (i, 2, n) L[i] = read(), Log2[i] = Log2[i >> 1] + 1; Init();
  42. int m = read();
  43. For (i, 1, m) {
  44. int l = read(), r = read(), x = read();
  45. int ans = Calc(l, x) - Calc(r + 1, x), len = r - l + 1, g = __gcd(ans, len);
  46. printf ("%d/%d\n", ans / g, len / g);
  47. }
  48. return 0;
  49. }

LOJ #6435. 「PKUSC2018」星际穿越(倍增)的更多相关文章

  1. LOJ 6435 「PKUSC2018」星际穿越——DP+倍增 / 思路+主席树

    题目:https://loj.ac/problem/6435 题解:https://www.cnblogs.com/HocRiser/p/9166459.html 自己要怎样才能想到怎么做呢…… dp ...

  2. loj#6435. 「PKUSC2018」星际穿越(倍增)

    题面 传送门 题解 我们先想想,在这个很特殊的图里该怎么走最短路 先设几个量,\(a_i\)表示\([a_i,i-1]\)之间的点都和\(i\)有边(即题中的\(l_i\)),\(l\)表示当前在计算 ...

  3. 【LOJ】#6435. 「PKUSC2018」星际穿越

    题解 想出70的大众分之后就弃疗了,正解有点神仙 就是首先有个比较显然的结论,就是要么是一直往左走,要么是走一步右边,然后一直往左走 根据这个可以结合RMQ写个70分的暴力 我们就考虑,最优的话显然是 ...

  4. #6435. 「PKUSC2018」星际穿越

    考场上写出了70分,现在填个坑 比较好写的70分是这样的:(我考场上写的贼复杂) 设\(L(i)=\min_{j=i}^nl(j)\) 那么从i开始向左走第一步能到达的就是\([l(i),i-1]\) ...

  5. 「PKUSC2018」星际穿越 (70分做法)

    5371: [Pkusc2018]星际穿越 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 27  Solved: 11[Submit][Status] ...

  6. 「PKUSC2018」星际穿越(倍增)

    倍增好题啊! 我们我们预处理 \(f[x][i]\) 表示 \(x\) 点最左到达的端点,\(sum[x][i]\) 表示 \(x\) 点最左到达的端点时 \(f[x][i]\sim x\) 的答案, ...

  7. 「PKUSC2018」星际穿越

    传送门 Solution  倍增 Code  #include <bits/stdc++.h> #define reg register #define ll long long usin ...

  8. LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)

    题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...

  9. LOJ #6432. 「PKUSC2018」真实排名(组合数)

    题面 LOJ #6432. 「PKUSC2018」真实排名 注意排名的定义 , 分数不小于他的选手数量 !!! 题解 有点坑的细节题 ... 思路很简单 , 把每个数分两种情况讨论一下了 . 假设它为 ...

随机推荐

  1. Luogu3959 NOIP2017 宝藏 状压DP

    题目传送门:https://www.luogu.org/problemnew/show/P3959 题意:给出一个有$N$个点的图,求其中的一个生成树(指定一个点为根),使得$\sum\limits_ ...

  2. Python3.x:Selenium+PhantomJS爬取带Ajax、Js的网页及获取JS返回值

    前言 现在很多网站的都大量使用JavaScript,或者使用了Ajax技术.这样在网页加载完成后,url虽然不改变但是网页的DOM元素内容却可以动态的变化.如果处理这种网页是还用requests库或者 ...

  3. CentOS搭建NAT和DHCP服务,实现共享上网

    什么是NAT? NAT(Network address translation)即网络地址转换,作为一种过渡解决手段,可以用来减少对全球合法IP地址的需求.简单的说,NAT就是在内部专用网络中使用内部 ...

  4. KVM虚拟机管理——资源调整

    1. 概述2. 计算资源调整2.1 调整处理器配置2.2 调整内存配置3. 存储资源调整3.1 根分区扩展3.2 添加磁盘4. 网络资源调整 1. 概述 KVM在使用过程中,会涉及到计算(CPU,内存 ...

  5. nginx通过https方式反向代理多实例tomcat

    案例说明:前面一层nginx+Keepalived部署的LB,后端两台web服务器部署了多实例的tomcat,通过https方式部署nginx反向代理tomcat请求.配置一如下: 1)LB层的ngi ...

  6. Adobe Photoshop CC 2015使用及扩展工具

    VAdobe Photoshop CC 2015: 简称"PS",是由Adobe Systems开发和发行的图像处理软件 扩展工具: Cuuterman:切图插件: 一个一个切图, ...

  7. visual studio2013安装及测试

    visual studio2013自同学处拷贝安装至本机,由于安装包较大采用了双重压缩,解压时费了点时间,安装过程更是用了一个小时之久. 1.安装环境: 本机配置:Windows8,Intel(R)C ...

  8. 《Linux内核设计与实现》读书笔记——第四章

    标签(空格分隔): 20135321余佳源 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统. ...

  9. 发布阶段 github和360移动助手及总结

    经过一系列的冲刺和加工 最激动人心的无非在发布平台上公布上自己辛苦奋斗了一个周期的产品,这个时候的我们就像Iphone 6发布会上得CEO,为自己的产品完美画上了研发的句号. 接下来的日子就是准备ve ...

  10. 【转】C语言宏高级用法 [总结]

    1.前言  今天看代码时候,遇到一些宏,之前没有见过,感觉挺新鲜.如是上网google一下,顺便总结一下,方便以后学习和运用.C语言程序中广泛的使用宏定义,采用关键字define进行定义,宏只是一种简 ...