zoukankan      html  css  js  c++  java
  • 【JZOJ4665】【CF407E】k-d-sequence

    题目链接:k-d-sequence

    题目大意

    给一个长度为(n)的序列(a),要你找一个最长的区间,使得将区间内的数排序以后,最多加(k)个数使它构成公差为(d)的等差数列。长度相同取左端点最靠左的。
    (nleq 200000,kleq 200000,dleq 10^9,|a_i|leq 10^9)

    解析

    一个小插曲:这题JZOJ上的数据很不靠谱,随意就水过了。CF上的数据强一点。

    首先我们来分析一段区间([l,r])怎么样才满足条件:

    • 没有相等的数(区间长度(>1)
    • 所有数模(d)同余(这样才能保证公差为(d)
    • (frac{max_{i=l}^{r} {a_i}-min_{i=l}^{r} {a_i}}{d}+1leq r-l+1+k)

    前两个条件保证这个序列能够通过补数成为公差为(d)的等差数列,第三个条件保证要补的数不超过(k)个。

    对于前两个条件,我们可以用一个数组maxr[i]表示以(i)为左端点,满足这两个条件的最远右端点,这个值具有单调性,可以(O(n))做出来。

    对于第三个条件,我们先把所有的(a_i)除以(d),然后变一下式子,得到:

    [max_{i=l}^{r}{a_i}-min_{i=l}^{r}{a_i} - r leq k-l ]

    此时式子右边仅跟(l)有关,我们考虑倒序枚举(l),若能用某个数据结构维护每个(r)对应的(b_r=max_{i=l}^{r}{a_i}-min_{i=l}^{r}{a_i} - r),就好做了。

    考虑(l)的移动使(b_r)发生的变化,用个单调栈维护(a_l)作为最大(小)值向右最远延伸到的位置(f_l),那么现在(a_l)是老大了,原来的假老大都得消除影响,可以发现一个数作为最大值影响的是一个区间,我们要把一个区间减掉某个数再加上某个数,这不显然用线段树维护吗?

    那么问题来了,如何查询?我们要一个最右的端点(r)使得(b_rleq k-l),并且还要满足(lleq rleq maxr[l])

    其实维护一个区间最小值就行了,在线段树上判断右边(b_r)的最小值是否(leq k-l),是就往右走。为了防止跳到(l)之前或者(maxr[l])之后去,我们先把这两段加上无穷大,做完再减掉就行了。

    注意,单调栈的过程是跟着倒序枚举(l)的过程一起做的。

    此外记得特判(d=0)的情况,不然要出锅。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define lson rt << 1
    #define rson rt << 1 | 1
    using namespace std;
    
    typedef long long ll;
    const int N = 200007;
    const ll INF = 0x3f3f3f3f;
    ll min(ll a, ll b) { return a < b ? a : b; }
    
    int ans = 1, ansl = 1;
    int n, k, len, maxr[N], c[N], mo[N];
    ll d, a[N], b[N];
    int buc[N];
    
    int top[2], stk[N][2];
    
    ll mi[N * 4], inc[N * 4];
    void upd(int rt) { mi[rt] = min(mi[lson], mi[rson]); }
    void build(int rt, int l, int r)
    {
    	if (l == r) { mi[rt] = -l; return; }
    	int mid = l + r >> 1;
    	build(lson, l, mid), build(rson, mid + 1, r), upd(rt);
    }
    void down(int rt, int l, int r)
    {
    	if (!inc[rt]) return;
    	if (l != r) inc[lson] += inc[rt], inc[rson] += inc[rt];
    	mi[rt] += inc[rt], inc[rt] = 0;
    }
    void modify(int rt, int l, int r, int ql, int qr, ll v)
    {
    	down(rt, l, r);
    	if (ql <= l && r <= qr) { inc[rt] += v; return; }
    	int mid = l + r >> 1;
    	if (ql <= mid) modify(lson, l, mid, ql, qr, v);
    	if (mid + 1 <= qr) modify(rson, mid + 1, r, ql, qr, v);
    	down(lson, l, mid), down(rson, mid + 1, r), upd(rt);
    }
    int getit(int rt, int l, int r, ll v)
    {
    	down(rt, l, r);
    	if (l == r) return mi[rt] <= v ? l : -1;
    	int mid = l + r >> 1;
    	down(lson, l, mid), down(rson, mid + 1, r);
    	if (mi[rson] <= v) return getit(rson, mid + 1, r, v);
    	else return getit(lson, l, mid, v);
    }
    
    void doit()
    {
    	for (int i = 1; i <= n; i++)
    	{
    		int j = i;
    		while (j < n && a[j + 1] == a[i]) j++;
    		if (j - i + 1 > ans) ans = j - i + 1, ansl = i;
    		else if (j - i + 1 == ans && i < ansl) ansl = i;
    		i = j;
    	}
    	printf("%d %d
    ", ansl, ansl + ans - 1);
    }
    
    int main()
    {
    	scanf("%d%d%I64d", &n, &k, &d); //cf的%I64d
    	for (int i = 1; i <= n; i++) scanf("%I64d", &a[i]), a[i] += 1e9;
    	if (d == 0) { doit(); return 0; }
    	memcpy(b, a, sizeof(a));
    	sort(b + 1, b + n + 1);
    	len = unique(b + 1, b + n + 1) - b - 1;
    	for (int i = 1; i <= n; i++) c[i] = lower_bound(b + 1, b + n + 1, a[i]) - b, mo[i] = a[i] % d;
    	buc[c[1]]++;
    	for (int i = 1, j = 1; i <= n; i++)
    	{
    		while (j + 1 <= n && mo[j + 1] == mo[i] && !buc[c[j + 1]]) j++, buc[c[j]]++;
    		maxr[i] = j, buc[c[i]]--;
    	}
    	build(1, 1, n);
    	stk[0][0] = stk[0][1] = n + 1;
    	for (int i = n; i; i--)
    	{
    		a[i] /= d;
    		if (!top[0]) modify(1, 1, n, i, n, -a[i]);
    		if (!top[1]) modify(1, 1, n, i, n, a[i]);
    		for (; top[0] && a[i] < a[stk[top[0]][0]]; top[0]--) modify(1, 1, n, stk[top[0]][0], stk[top[0] - 1][0] - 1, a[stk[top[0]][0]] - a[i]);
    		for (; top[1] && a[i] > a[stk[top[1]][1]]; top[1]--) modify(1, 1, n, stk[top[1]][1], stk[top[1] - 1][1] - 1, a[i] - a[stk[top[1]][1]]);
    		stk[++top[0]][0] = stk[++top[1]][1] = i;
    		if (maxr[i] < n) modify(1, 1, n, maxr[i] + 1, n, INF);
    		if (i > 1) modify(1, 1, n, 1, i - 1, INF);
    		int r = getit(1, 1, n, k - i);
    		if (r != -1 && r - i + 1 >= ans) ans = r - i + 1, ansl = i;
    		if (maxr[i] < n) modify(1, 1, n, maxr[i] + 1, n, -INF);
    		if (i > 1) modify(1, 1, n, 1, i - 1, -INF);
    	}
    	printf("%d %d
    ", ansl, ans + ansl - 1);
    	return 0;
    }
    
  • 相关阅读:
    Nginx负载均衡+代理+ssl+压力测试
    Nginx配置文件详解
    HDU ACM 1690 Bus System (SPFA)
    HDU ACM 1224 Free DIY Tour (SPFA)
    HDU ACM 1869 六度分离(Floyd)
    HDU ACM 2066 一个人的旅行
    HDU ACM 3790 最短路径问题
    HDU ACM 1879 继续畅通工程
    HDU ACM 1856 More is better(并查集)
    HDU ACM 1325 / POJ 1308 Is It A Tree?
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/11134731.html
Copyright © 2011-2022 走看看