首页 技术 正文
技术 2022年11月15日
0 收藏 975 点赞 4,777 浏览 2223 个字

「HNOI2018」转盘

现场推出了大部分结论但是只写了 \(40\) 分暴力,被贺指导踩爆,现在还有点怀念 HNOI2018 贺指导对着镜子荒野行动的日子,那几天他云球迷瞎**指点篮球,被送上指导称号一个。

解题思路

可以大力证明一定存在一种最优解只需要走一圈,假设存在一个最优解在某个时刻已经走了一圈回到出发点还剩下一些点没有被标记,那么最终还需要走到这些点标记一遍,这样的时间开销和在需要被标记的点之前等到它可以再走是等价的,所以一定存在一种最优解是在起始点等若干时刻然后一遍走完的。

于是可以把环倍长为 \(T_1,T_2\dots T_{2n}\) ,枚举一个起始点 \(1\leq s \leq n\) ,贡献就是

\[(n-1)+\max_{s\leq i < s+n} (T_i-(i-s)) \\ = (n-1)+ s+\max_{s\leq i < s+n} (T_i-i)
\\ ans = n-1+\min_{1\leq s \leq n}(s+\max_{s\leq i < s+n} (T_i-i))
\]

这个东西是所有长度为 \(n\) 的区间的贡献的 \(\min\) ,不太好维护,观察发现每一个区间后面的元素必然会小于区间内元素的 \(\max\) ,因为后面的元素都是倍长后没有被用到的 \(T_{i+n}\) ,显然 \(T_{i+n}-i-n<T_i-i\) 。

于是问题就转化为对于每一个后缀算贡献取 \(\min\) ,经典线段树维护单调栈求解即可。

具体来说,令 \(Ans(l,r)\) 为左端点在 \([l,mid]\) 的所有后缀贡献的 \(\min\) ,再维护一下区间 \(\max\) ,那么可以线段树二分找到 \(\max[mid+1,r]\) 在 \([l,mid]\) 中的位置 \(pos\) ,那么 \(pos\) 及以后的贡献是 \(pos+\max[mid+1,r]\) ,\(pos\) 之前的贡献就是那个节点原先的 \(Ans\) 。

这样搞一搞更新需要额外的一个 \(\log\) ,总时间复杂度 \(\mathcal O(n\log^2n)\) 。

code

/*program by mangoyang*/
#pragma GCC optimize("O2", "Ofast")
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 200005;
int t[N], n, m, p;
namespace Seg{
#define lson (u << 1)
#define rson (u << 1 | 1)
#define mid ((l + r) >> 1)
int mx[N<<2], s[N<<2];
inline int find(int u, int l, int r, int x){
if(l == r) return l + max(mx[u], x);
if(mx[rson] >= x)
return min(s[u], find(rson, mid + 1, r, x));
return min(mid + 1 + x, find(lson, l, mid, x));
}
inline void update(int u, int l, int r){
mx[u] = max(mx[lson], mx[rson]);
s[u] = find(lson, l, mid, mx[rson]);
}
inline void build(int u, int l, int r){
if(l == r) return (void) (mx[u] = t[l], s[u] = l + t[l]);
build(lson, l, mid), build(rson, mid + 1, r);
update(u, l, r);
}
inline void modify(int u, int l, int r, int pos, int x){
if(l == r) return (void) (mx[u] = x, s[u] = l + x);
if(pos <= mid) modify(lson, l, mid, pos, x);
else modify(rson, mid + 1, r, pos, x);
update(u, l, r);
}
}
int main(){
read(n), read(m), read(p);
for(int i = 1; i <= n; i++) read(t[i]);
for(int i = 1; i <= n; i++) t[i+n] = t[i];
for(int i = 1; i <= 2 * n; i++) t[i] -= i;
Seg::build(1, 1, 2 * n);
int lastans = Seg::s[1] + n - 1;
printf("%d\n", lastans);
for(int i = 1, x, y; i <= m; i++){
read(x), read(y), x ^= lastans * p, y ^= lastans * p;
Seg::modify(1, 1, 2 * n, x, y - x);
Seg::modify(1, 1, 2 * n, x + n, y - x - n);
printf("%d\n", lastans = Seg::s[1] + n - 1);
}
return 0;
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,105
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,582
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,429
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,836
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,919