「6月雅礼集训 2017 Day11」jump
【题目大意】
有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[\max(1, i-x_i), \min(i+x_i, n)]$中。
定义$(i,j)$的距离表示从$i$到$j$经过多少步,从$j$到$i$经过多少步,这两个取最小值。
求任意两点间最大的距离。
$1\leq n \leq 10^5, 1 \leq x_i < n$
【题解】
每个点经过若干次能过到达的,显然是一个区间。
考虑倍增,$[L_{x,i}, R_{x,i}]$表示从$x$开始,经过$2^i$步,到达的区间。
这个可以通过倍增+线段树来解决,线段树维护最小值和最大值,对应区间两个端点。
对于询问,我们二分答案后,问题转化与是否能找出一个点对步数$> x$($x$为我们二分的值)
通过倍增我们可以求出每个点经过$x$步后到达的区间,设为$[L', R']$。那么不能到达的就是$[1, L']$和$[R',n]$。
问题转化为,$[1, L']$和$[R', n]$是否可以经过$x$步以内到达$i$这个点。
这个可以通过记录一个前缀和以及一个后缀和来解决。
这里的“和”指的是区间交。
然后就行啦!
时间复杂度$O(nlog^3n)$
upd: 线段树有点问题,已经修正
=========================分割线=============================
upd: 之前的复杂度有点问题,是$O(nlog^3n)$的,理论上是过不去的,但是常数太优秀了(逃
我们可以把二分改为从高位往低位确定答案的每位,每次就不需要倍增了,就在之前的基础上,直接做即可。这样就是$O(nlog^2n)$的了
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; const int N = 1e5 + , M = 2e5 + ;
const int inf = 1e9; # define bit(x, i) (((x) >> (i)) & ) int n;
struct pa {
int x, y;
pa() {}
pa(int x, int y) : x(x), y(y) {}
friend pa operator + (pa a, pa b) {
return pa(min(a.x, b.x), max(a.y, b.y));
}
friend pa operator - (pa a, pa b) {
return pa(max(a.x, b.x), min(a.y, b.y));
}
}; inline bool out(int x, pa t) {
return x < t.x || x > t.y;
} int L[][N], R[][N]; struct SMT {
pa w[M << ];
# define ls (x<<)
# define rs (x<<|)
inline void set(int n) {
for (int i=; i<=n+n; ++i) w[i] = pa(inf, -inf);
}
inline void build(int x, int l, int r, int p) {
if(l == r) {
w[x] = pa(L[p][l], R[p][l]);
return ;
}
int mid = l+r>>;
build(ls, l, mid, p);
build(rs, mid+, r, p);
w[x] = w[ls] + w[rs];
// printf("p = %d, [%d, %d], [%d, %d]\n", p, l, r, w[x].x, w[x].y);
}
inline pa query(int x, int l, int r, int L, int R) {
if(L <= l && r <= R) return w[x];
int mid = l+r>>;
if(L > mid) return query(rs, mid+, r, L, R);
else if (R <= mid) return query(ls, l, mid, L, R);
else return query(ls, l, mid, L, mid) + query(rs, mid+, r, mid+, R);
}
# undef ls
# undef rs
}T[]; // have dis > x
pa c[N];
pa t[N];
pa f[N], g[N]; inline bool chk(int x) {
pa tmp;
for (int i=; i<=n; ++i) {
tmp.x = t[i].x, tmp.y = t[i].y;
tmp = T[x].query(, , n, tmp.x, tmp.y);
c[i] = tmp;
// printf(" i = %d, [%d, %d]\n", i, c[i].x, c[i].y);
}
f[] = c[]; g[n] = c[n];
for (int i=; i<=n; ++i) f[i] = f[i-] - c[i];
for (int i=n-; i; --i) g[i] = g[i+] - c[i];
for (int i=; i<=n; ++i) {
if(c[i].x == && c[i].y == n) continue;
// [1, c[i].x-1], [c[i].y+1], n]
if(c[i].x != ) {
if(out(i, f[c[i].x-])) return true;
}
if(c[i].y != n) {
if(out(i, g[c[i].y+])) return true;
}
}
return false;
}
// # include <time.h>
int main() {
freopen("jump.in", "r", stdin);
freopen("jump.out", "w", stdout);
cin >> n;
for (int i=; i<=; ++i) T[i].set(n);
for (int i=, x; i<=n; ++i) {
scanf("%d", &x);
L[][i] = max(i-x, );
R[][i] = min(i+x, n);
}
pa tem;
for (int j=; j<=; ++j) {
T[j-].build(, , n, j-);
for (int i=; i<=n; ++i) {
tem = T[j-].query(, , n, L[j-][i], R[j-][i]);
L[j][i] = tem.x, R[j][i] = tem.y;
}
}
T[].build(, , n, ); // for (int j=0; j<=5; ++j)
// for (int i=1; i<=n; ++i) printf("%d %d L = %d, R = %d\n", i, j, L[j][i], R[j][i]); int l = , r = n-, mid, ans = ;
for (int i=; i<=n; ++i) t[i] = pa(i, i);
for (int i=; ~i; --i) {
if(chk(i)) {
for (int j=; j<=n; ++j)
t[j] = c[j];
ans += (<<i);
}
} cout << ans + << endl;
// cerr << clock() << " ms\n";
return ;
}
/*
8
7 1 1 1 1 1 1 7 10
2 2 1 2 2 1 2 2 1 2
*/
下面是$O(nlog^3n)$的代码
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; const int N = 1e5 + , M = 2e5 + ;
const int inf = 1e9; # define bit(x, i) (((x) >> (i)) & ) int n;
struct pa {
int x, y;
pa() {}
pa(int x, int y) : x(x), y(y) {}
friend pa operator + (pa a, pa b) {
return pa(min(a.x, b.x), max(a.y, b.y));
}
friend pa operator - (pa a, pa b) {
return pa(max(a.x, b.x), min(a.y, b.y));
}
}; inline bool out(int x, pa t) {
return x < t.x || x > t.y;
} int L[][N], R[][N]; struct SMT {
pa w[M << ];
# define ls (x<<)
# define rs (x<<|)
inline void set(int n) {
for (int i=; i<=n+n; ++i) w[i] = pa(inf, -inf);
}
inline void build(int x, int l, int r, int p) {
if(l == r) {
w[x] = pa(L[p][l], R[p][l]);
return ;
}
int mid = l+r>>;
build(ls, l, mid, p);
build(rs, mid+, r, p);
w[x] = w[ls] + w[rs];
// printf("p = %d, [%d, %d], [%d, %d]\n", p, l, r, w[x].x, w[x].y);
}
inline pa query(int x, int l, int r, int L, int R) {
if(L <= l && r <= R) return w[x];
int mid = l+r>>;
if(L > mid) return query(rs, mid+, r, L, R);
else if (R <= mid) return query(ls, l, mid, L, R);
else return query(ls, l, mid, L, mid) + query(rs, mid+, r, mid+, R);
}
# undef ls
# undef rs
}T[]; // have dis > x
pa c[N]; pa f[N], g[N]; inline bool chk(int x) {
// cout << "x = " << x << endl;
pa t;
for (int i=; i<=n; ++i) {
t.x = t.y = i;
for (int j=; ~j; --j)
if(bit(x, j)) t = T[j].query(, , n, t.x, t.y);
c[i] = t;
// printf(" i = %d, [%d, %d]\n", i, c[i].x, c[i].y);
}
f[] = c[]; g[n] = c[n];
for (int i=; i<=n; ++i) f[i] = f[i-] - c[i];
for (int i=n-; i; --i) g[i] = g[i+] - c[i];
for (int i=; i<=n; ++i) {
if(c[i].x == && c[i].y == n) continue;
// [1, c[i].x-1], [c[i].y+1], n]
if(c[i].x != ) {
if(out(i, f[c[i].x-])) return true;
}
if(c[i].y != n) {
if(out(i, g[c[i].y+])) return true;
}
}
return false;
}
// # include <time.h>
int main() {
freopen("jump.in", "r", stdin);
freopen("jump.out", "w", stdout);
cin >> n;
for (int i=; i<=; ++i) T[i].set(n);
for (int i=, x; i<=n; ++i) {
scanf("%d", &x);
L[][i] = max(i-x, );
R[][i] = min(i+x, n);
}
pa tem;
for (int j=; j<=; ++j) {
T[j-].build(, , n, j-);
for (int i=; i<=n; ++i) {
tem = T[j-].query(, , n, L[j-][i], R[j-][i]);
L[j][i] = tem.x, R[j][i] = tem.y;
}
}
T[].build(, , n, ); // for (int j=0; j<=5; ++j)
// for (int i=1; i<=n; ++i) printf("%d %d L = %d, R = %d\n", i, j, L[j][i], R[j][i]); int l = , r = n-, mid, ans;
while() {
if(r-l <= ) {
for (int i=r; i>=l; --i)
if(chk(i)) {
ans = i;
break;
}
break;
}
mid = l+r>>;
if(chk(mid)) l = mid;
else r = mid;
} cout << ans + << endl;
// cerr << clock() << " ms\n";
return ;
}
/*
8
7 1 1 1 1 1 1 7 10
2 2 1 2 2 1 2 2 1 2
*/
「6月雅礼集训 2017 Day11」jump的更多相关文章
- 「6月雅礼集训 2017 Day11」delight
[题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...
- 「6月雅礼集训 2017 Day11」tree
[题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...
- 「6月雅礼集训 2017 Day10」quote
[题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...
- 「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)
原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687 [题目大意] 给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 | ...
- 「6月雅礼集训 2017 Day10」perm(CodeForces 698F)
[题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多 ...
- 「6月雅礼集训 2017 Day8」route
[题目大意] 给出平面上$n$个点,求一条连接$n$个点的不相交的路径,使得转换的方向符合所给长度为$n-2$的字符串. $n \leq 5000$ [题解] 考虑取凸包上一点,然后如果下一个是‘R' ...
- 「6月雅礼集训 2017 Day8」gcd
[题目大意] 定义times(a, b)表示用辗转相除计算a和b的最大公约数所需步骤. 那么有: 1. times(a, b) = times(b, a) 2. times(a, 0) = 0 3. ...
- 「6月雅礼集训 2017 Day8」infection
[题目大意] 有$n$个人,每个人有一个初始位置$x_i$和一个速度$v_i$,你需要选择若干个人来感染一个傻逼病毒. 当两个人相遇(可以是正面和背面),傻逼病毒会传染,求经过无限大时间后,传染完所有 ...
- 「6月雅礼集训 2017 Day7」电报
[题目大意] 有n个岛屿,第i个岛屿有有向发射站到第$p_i$个岛屿,改变到任意其他岛屿需要花费$c_i$的代价,求使得所有岛屿直接或间接联通的最小代价. $1 \leq n \leq 10^5, 1 ...
随机推荐
- 《梦断代码Dreaming In Code》阅读笔记(三)
最后这几章感觉上更多是从软件完成整体上来讲的.比如说技术.方法等. 在我看来,其实一个团队一直坚持一种好的.先进的方法是不可少的.如果一个优秀的团队刚愎自用,只随着成员们喜好发展,那不能长久.比如说, ...
- SOA是什么为什么要面向服务编程
SOA(面向服务的架构),Service-Oriented Architecture,面向服务的体系结构. 也就是以服务为核心的架构.这里需要理解什么是服务. 比如你有一个读取通知的方法: publi ...
- iOS- UIScrollView、UIPageControl分页浏览图片
1.先介绍下UIScrollView的常见属性 @property(nonatomic) CGPoint contentOffset; // 记录UIScrollView滚动的位置 @property ...
- GPS定位,根据经纬度查询附近地点的经纬度-sql方法实现
根据当前所在的坐标点也即经纬度,查找数据库中附近5公里或10公里附近的所有信息的实现,经过查找资料,原来是我高二学的,就是求弦长,数学忘完了,没想到数学还这么有用,数学啊 真是用途太大了. 用到的什么 ...
- winform 删除,清空指定文件夹上的所有文件或文件夹
//递归删除文件夹及子文件C#代码: public void DeleteFolder(string dir) { if (Directory.Exists(dir)) //如果存在这个文件夹删除之 ...
- git工具SourceTree工作流
分支模型 master 用来最终上线的分支,最终发布版本,整个项目中有且只有一个 develop 项目中用来开发的分支,原则上项目中有且只有一个,develop 分支下面的分支是经常变化的,会创建新的 ...
- Jenkins系列-Jenkins插件备份
Jenkins管理插件 为了让所有的插件在 Jenkins 内可用,所有插件的列表可以访问链接 − https://wiki.jenkins-ci.org/display/JENKINS/Plugin ...
- [OS] 线程相关知识点
操作系统中引入进程的目的,是为了描述和实现多个程序的并发执行,以改善资源利用率以及提高系统吞吐量.那为什么还需要引入线程呢?下面我们先来回顾一下什么是进程: 进程有两个基本属性:·资源的拥有者:给每个 ...
- 第27天:js-表单获取焦点和数组声明遍历
一.表单 1.this指事件的调用者2.input.value 表单更换内容3.innerHTML更换盒子里的内容,文字.标签都能换.4.isNaN("12")如果里面的不是个数字 ...
- Python 日志输出中添加上下文信息
Python日志输出中添加上下文信息 除了传递给日志记录函数的参数(如msg)外,有时候我们还想在日志输出中包含一些额外的上下文信息.比如,在一个网络应用中,可能希望在日志中记录客户端的特定信息,如: ...