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;
    }
    
  • 相关阅读:
    Golang Failpoint 的设计与实现
    没涉及到最值求解;观点:矩阵乘法无法表达出结果。 现实生活中事件、现象的数学表达
    多元微分学 枚举破解15位路由器密码 存储空间限制 拆分减长,求最值 数据去重
    ARP Poisoning Attack and Mitigation Techniques ARP欺骗 中间人攻击 Man-In-The-Middle (MITM) attack 嗅探 防范 Can one MAC address have two different IP addresses within the network?
    The C10K problem
    HTTP Streaming Architecture HLS 直播点播 HTTP流架构
    现代IM系统中消息推送和存储架构的实现
    现代IM系统中的消息系统架构
    长连接锁服务优化实践 C10K问题 nodejs的内部构造 limits.conf文件修改 sysctl.conf文件修改
    doubleclick cookie、动态脚本、用户画像、用户行为分析和海量数据存取 推荐词 京东 电商 信息上传 黑洞 https://blackhole.m.jd.com/getinfo
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/11134731.html
Copyright © 2011-2022 走看看