zoukankan      html  css  js  c++  java
  • 「题解」Codeforces 407E k-d-sequence

    题意:求最长区间使得加入 (k) 个数后 sort 后最后为一个公差为 (d) 的等差数列。多解输出 (l) 最小的答案。

    (n,kleq 2 imes 10^5,0leq dleq 10^9)

    • (d=0) 的情况特判一下,找最长的值都相同的段即可

    • (d eq 0) 的情况:

    是公差为 (d) 等差数列需要满足两个条件:

    • (mod d) 相同;
    • 值两两不同。

    可以单独处理每个极长的同余的段,然后分开处理:

    先都整除一下 (d),问题都转化成处理公差 (d)(1) 的情况。

    这个区间合法要求 (max-min+1-(R-L+1)leq k),枚举 (r) 统计最小的 (l) 使得:

    • ([L,R]) 内元素无重复;

    • (max-min+1-(R-L+1)leq k)

    其中 (max)/(min) 为区间 ([L,R]) 的最大/小值

    无重复的条件很好做,记录一下每个值上次出现的位置,然后记录一下 (l) 的下界 (T)

    (w_L=max(L,R)-min(L,R)+L)

    ([T+1,R]) 中最左的 (L) 使得 (w_Lleq k+R),假如我们可以快速维护 (w) ,就可以解决这个问题。

    怎样维护 (w)

    注意 (max(L,R)) 是递减的,(min) 也类似。(max(L,R)) 可以维护一个单调栈,栈中的每个点都代表一段区间,它们的 (max(L,R)) 是这个栈中的这个元素。那么每次弹出的时候修改这个区间的 (w) 即可。

    操作是区间加减,需要支持的查询为区间最左侧小于等于某个数的位置,这是个经典问题,记录一下区间最小值即可。

    均摊下来复杂度是对的,操作数仅有 (mathcal{O}(n)) 个。

    实现上有几个小细节,对于每个同余段重新建一棵大小为这个段长度的树,如果每次都 (mathcal{O}(n)) 建树,复杂度是错误的。(a_i) 有负数,提前全加上 (10^9) 转化成非负数,不影响答案。

    综上所述,我们完美的解决了这个问题,时间复杂度 (O(nlog n))

    //Code by do_while_true
    #include<iostream>
    #include<cstdio>
    #include<map>
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T &read(T &r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = (r << 3) + (r <<1) + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    const int N = 200010;
    const int INF = 0x7fffffff;
    int n, k, d;
    int a[N];
    std::map<int, int>pre; 
    #define tl tree[x].l
    #define tr tree[x].r
    #define ls tree[x].lson
    #define rs tree[x].rson
    int trnt;
    struct SGT {
    	int l, r, sum, mn, tag, lson, rson;
    }tree[N << 1];
    inline void pushup(int x) { tree[x].mn = Min(tree[ls].mn, tree[rs].mn); }
    inline void pushdown(int x) {
    	if(tree[x].tag) {
    		int &p = tree[x].tag;
    		tree[ls].mn += p; tree[rs].mn += p;
    		tree[ls].tag += p; tree[rs].tag += p;
    		p = 0; 
    	}
    }
    int build(int l, int r) {
    	int x = ++trnt; tl = l; tr = r;
    	tree[x].mn = tree[x].tag = tree[x].lson = tree[x].rson = 0;
    	if(l == r) return x;
    	ls = build(l, (l + r) >> 1); rs = build(tree[ls].r+1, r);
    	return x;
    }
    void modify(int x, int l, int r, int v) {
    	if(tree[x].l >= l && tree[x].r <= r) {
    		tree[x].mn += v;
    		tree[x].tag += v;
    		return ;
    	}
    	pushdown(x);
    	int mid = (tr + tl) >> 1;
    	if(mid >= l) modify(ls, l, r, v);
    	if(mid < r) modify(rs, l, r, v);
    	pushup(x); 
    }
    int query(int x, int l, int r, int v) {
    	if(tree[x].mn > v) return INF;
    	if(tl >= l && tr <= r) {
    		if(tl == tr) return tl;
    		pushdown(x); int sumq = 0;
    		if(tree[ls].mn <= v) sumq = query(ls, l, r, v);
    		else sumq = query(rs, l, r, v);
    		pushup(x);
    		return sumq;
    	}
    	pushdown(x);
    	int mid = (tl + tr) >> 1, sumq;
    	if(r <= mid) sumq = query(ls, l, r, v);
    	else if(l > mid) sumq = query(rs, l, r, v);
    	else {
    		sumq = query(ls, l, r, v);
    		if(sumq == INF) sumq = query(rs, l, r, v);
    	}
    	pushup(x);
    	return sumq;
    }
    #undef tl
    #undef tr
    #undef ls
    #undef rs
    int L[N], R[N], bcnt, ansl = 1, ansr = 1;
    int st1p[N], st1x[N], top1;
    int st2p[N], st2x[N], top2;
    int down;
    signed main() {
    //	freopen("in.txt", "r", stdin);
    	read(n); read(k); read(d);
    	if(!d) {
    		for(int i = 1; i <= n; ++i) read(a[i]);
    		int l = 1;
    		for(int i = 2; i <= n; ++i) {
    			if(a[i] != a[i-1]) {
    				if(i - l > ansr - ansl + 1) ansl = l, ansr = i-1;
    				l = i;
    			}
    		}
    		printf("%d %d
    ", ansl, ansr);
    		return 0;
    	}
    	for(int i = 1; i <= n; ++i) read(a[i]), a[i] += 1000000000;
    	L[bcnt = 1] = 1;
    	for(int i = 2; i <= n; ++i) {
    		if(a[i] % d != a[i-1] % d) {
    			R[bcnt] = i-1;
    			L[++bcnt] = i;
    		}
    	}
    	R[bcnt] = n;
    	for(int i = 1; i <= bcnt; ++i) {
    		if(R[i] - L[i] == 0) continue ;
    		int nowl = 1, nowr = 0;
    		pre.clear();
    		top1 = top2 = 0; trnt = 0; down = 1;
    		build(1, R[i] - L[i] + 1);
    		for(int j = L[i]; j <= R[i]; ++j) a[j] /= d;
    		for(int j = L[i]; j <= R[i]; ++j) {
    			if(pre[a[j]]) down = Max(down, pre[a[j]]-L[i]+2);
    			pre[a[j]] = j;
    			while(top1 && st1x[top1] <= a[j]) modify(1, st1p[top1-1]+1, st1p[top1], -st1x[top1]), --top1;
    			while(top2 && st2x[top2] >= a[j]) modify(1, st2p[top2-1]+1, st2p[top2], st2x[top2]), --top2;
    			st1x[++top1] = a[j]; st1p[top1] = j-L[i]+1;
    			st2x[++top2] = a[j]; st2p[top2] = j-L[i]+1;
    			modify(1, st1p[top1-1]+1, st1p[top1], st1x[top1]);
    			modify(1, st2p[top2-1]+1, st2p[top2], -st2x[top2]);
    			modify(1, j-L[i]+1, j-L[i]+1, j);
    			int pl = query(1, down, j-L[i]+1, k+j);
    			if(pl != INF && j - (pl+L[i]-1) + 1 > nowr - nowl + 1) nowl = pl+L[i]-1, nowr = j;
    		}
    		if(nowr - nowl + 1 > ansr - ansl + 1) ansl = nowl, ansr = nowr; 
    	}
    	printf("%d %d
    ", ansl, ansr);
    	return 0;
    } 
    
  • 相关阅读:
    kubernetes安全机制
    Django 与 Vue交互跨域问题解决
    ELK收集Kubernetes平台日志
    minikube 安装
    k8s安装教程
    Go 语言Map(集合)
    Go 语言类型转换
    Go 语言递归函数
    今天学习:CSS中的类class和标识id选择符(.和#号) 第一季
    人工智能星际争霸2教程
  • 原文地址:https://www.cnblogs.com/do-while-true/p/14968459.html
Copyright © 2011-2022 走看看