zoukankan      html  css  js  c++  java
  • 「HNOI2018」转盘

    「HNOI2018」转盘

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

    解题思路

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

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

    [(n-1)+max_{sleq i < s+n} (T_i-(i-s)) \ = (n-1)+ s+max_{sleq i < s+n} (T_i-i) \ ans = n-1+min_{1leq s leq n}(s+max_{sleq 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(nlog^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
    ", 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
    ", lastans = Seg::s[1] + n - 1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    将指定json格式的内容,写入文件中,构造测试数据
    shell对比用=时 记得加空格
    scp带私钥使用以及免密配置
    kafka知识补充
    根据frm和ibd文件恢复数据库表结构和数据
    登录页面 逻辑:当用户进来的时候, 全局检查一下是否有用户的信息,如果用则显示用户信息页面;没有,则显示用户登录页面
    理解Spring 容器、BeanFactory 以及 ApplicationContext
    Java 中 CAS
    volatile 关键字
    JenKins docker 集群
  • 原文地址:https://www.cnblogs.com/mangoyang/p/10486421.html
Copyright © 2011-2022 走看看