「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;
}

「HNOI2018」转盘的更多相关文章

  1. Loj #2495. 「AHOI / HNOI2018」转盘

    Loj #2495. 「AHOI / HNOI2018」转盘 题目描述 一次小 G 和小 H 原本准备去聚餐,但由于太麻烦了于是题面简化如下: 一个转盘上有摆成一圈的 \(n\) 个物品(编号 \(1 ...

  2. 「AHOI / HNOI2018」转盘 解题报告

    「AHOI / HNOI2018」转盘 可能是我语文水平不太行... 首先可以猜到一些事实,这个策略一定可以被一个式子表示出来,不然带修修改个锤子. 然后我们发现,可以枚举起点,然后直接往前走,如果要 ...

  3. 「HNOI2018」毒瘤

    「HNOI2018」毒瘤 解题思路 先考虑只有一棵树的情况,经典独立集计数. \[ dp[u][0]=\prod (dp[v][0]+dp[v][1]) \\ dp[u][1]=\prod dp[v] ...

  4. 「HNOI2018」游戏

    「HNOI2018」游戏 解题思路 首先没有锁上的门可以缩点缩掉,然后对于一扇锁上的门,如果钥匙在左边,那么右边就永远不可能到达左边,同理如果钥匙在右边,左边就永远不可能到达右边. 然后考虑一个暴力的 ...

  5. 【LOJ】#2495. 「AHOI / HNOI2018」转盘

    题面 题解 考虑我肯定是从一个人出发,开始依次标记,而不会跳过某个人,因为如果我跳过了,那么我之后回来还需要标记它,比不上我等完它再一直走到最后(因为多了走一圈之后走回它的代价) 我们倍长整个序列,我 ...

  6. Loj #2494. 「AHOI / HNOI2018」寻宝游戏

    Loj #2494. 「AHOI / HNOI2018」寻宝游戏 题目描述 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得 ...

  7. loj #2510. 「AHOI / HNOI2018」道路

    #2510. 「AHOI / HNOI2018」道路 题目描述 W 国的交通呈一棵树的形状.W 国一共有 n−1 个城市和 nnn 个乡村,其中城市从 111 到 n−1 编号,乡村从 111 到 n ...

  8. loj #2509. 「AHOI / HNOI2018」排列

    #2509. 「AHOI / HNOI2018」排列   题目描述 给定 nnn 个整数 a1,a2,…,an(0≤ai≤n),以及 nnn 个整数 w1,w2,…,wn.称 a1,a2,…,an 的 ...

  9. loj #2508. 「AHOI / HNOI2018」游戏

    #2508. 「AHOI / HNOI2018」游戏 题目描述 一次小 G 和小 H 在玩寻宝游戏,有 nnn 个房间排成一列,编号为 1,2,…,n,相邻房间之间都有 111 道门.其中一部分门上有 ...

随机推荐

  1. 弗罗贝尼乌斯範数(Frobenius norm)

    弗罗贝尼乌斯範数 对 p = 2,这称为弗罗贝尼乌斯範数(Frobenius norm)或希尔伯特-施密特範数( Hilbert–Schmidt norm),不过后面这个术语通常只用于希尔伯特空间.这 ...

  2. 终端多窗口分屏Terminator

    1.安装 Terminator最大的特点就是可以在一个窗口中打开多个终端 sudo apt-get install terminator 2.快捷键 Ctrl+Shift+E 垂直分割窗口 Ctrl+ ...

  3. CentOS6.6中安装telnet

    一.查看本机是否安装telnet rpm -qa | grep telnet 如果什么都不显示.说明你没有安装telnet 二.开始安装 yum install xinetd yum install ...

  4. Git的安装和使用(Linux)【转】

    转自:http://my.oschina.net/fhd/blog/354685 Git诞生于Linux平台并作为版本控制系统率先服务于Linux内核,因此在Linux上安装Git是非常方便的.可以通 ...

  5. 使用ubifs格式的根文件系统

    配置内核,使其支持ubifs文件系统 1)Device Drivers  --->Memory Technology Device (MTD) support  --->UBI - Uns ...

  6. Linux下简单粗暴使用rsync实现文件同步备份【转】

    这篇来说说如何安全的备份,还有一点不同的是上一篇是备份服务器拉取数据,这里要讲的是主服务器如何推送数据实现备份. 一.备份服务器配置rsync文件 vim /etc/rsyncd.conf #工作中指 ...

  7. javascript多投事件的处理 (转)

    出处 http://blog.csdn.net/dead_of_winter/article/details/1646367 尽管ecma标准指定了addEventListener这样的方法来实现事件 ...

  8. Hash 分布均衡算法

    1.移位实现 public static int GetIndex(string str, int count) { , (current, c) => (current << ) ...

  9. 安装pywin32模块

    1.先下载pywin32对于的版本 下载地址:python for windows extensions 2.选择自己对应的版本,我的是python3.5版本 注意注意注意:此处一定要看清楚自己的py ...

  10. UFLDL(五)自编码算法与稀疏性

    新教程内容太繁复,有空再看看,这节看的还是老教程: http://ufldl.stanford.edu/wiki/index.php/%E8%87%AA%E7%BC%96%E7%A0%81%E7%AE ...