• CodeForces 407E: k-d-sequence


    题目传送门:CF407E

    题意简述:

    给定非负整数 (k,d) 和一个长度为 (n)(1le nle 2 imes 10^5))的整数序列 (a)

    求这个序列中最长的一个连续子串 (a[l:r]) 满足:添加不超过 (k) 个整数,再排序后,可以形成公差为 (d) 的等差数列。

    若有多个满足条件取最左侧的那个。

    题解:

    首先特判 (d=0) 的情况,这时相当于求最长连续段。

    易发现若一些数要组成一个公差为 (d) 的等差数列,必须要满足这些数模 (d) 同余。

    所以依次考虑每个模 (d) 同余的连续子串,将其中每个数除以 (d) 向下取整,转化为 (d=1) 的情况。

    转化为一个经典问题,要求连续子串的值域满足某些条件,而条件仅和子串中的最值、子串端点的位置有关。

    假设子串为 (a[l:r]),这里的条件是:(max{a[l:r]}-min{a[l:r]}+lle k+r)(a[l:r]) 中无重复元素。

    考虑右端点 (r)(1) 开始逐步向右推,每次求出最佳的合法左端点位置。

    对于两个限制,前者使用两个单调栈和线段树解决,后者限定了一个 (l) 的下限,维护每个值的上一次出现位置,每次向右推时更新即可。

    求位置时需要查询一段区间内的最靠左的值 (le k+r) 的位置,这可以通过线段树维护最小值简单地做到。

    下面是代码,时间复杂度 (mathcal{O}(nlog n))

    #include <cstdio>
    #include <algorithm>
    
    const int MN = 200005;
    const int MS = 1 << 19 | 7;
    
    #define li (i << 1)
    #define ri (i << 1 | 1)
    #define mid ((l + r) >> 1)
    #define ls li, l, mid
    #define rs ri, mid + 1, r
    int mn[MS], tg[MS];
    inline void P(int i, int x) { mn[i] += x, tg[i] += x; }
    inline void pd(int i) { if (tg[i]) P(li, tg[i]), P(ri, tg[i]), tg[i] = 0; }
    void Build(int i, int l, int r) {
    	mn[i] = tg[i] = 0;
    	if (l == r) return ;
    	Build(ls), Build(rs);
    }
    void Mdf(int i, int l, int r, int a, int b, int x) {
    	if (r < a || b < l) return ;
    	if (a <= l && r <= b) return P(i, x);
    	pd(i), Mdf(ls, a, b, x), Mdf(rs, a, b, x);
    	mn[i] = std::min(mn[li], mn[ri]);
    }
    int Qur(int i, int l, int r, int a, int b, int x) {
    	if (r < a || b < l || mn[i] > x) return -1;
    	if (l == r) return l;
    	pd(i);
    	int lpos = Qur(ls, a, b, x);
    	return ~lpos ? lpos : Qur(rs, a, b, x);
    }
    
    int Ans, MaxLen;
    inline void Solve(int *A, int N, int K, int offset) {
    	if (N <= MaxLen) return ;
    	static int B[MN], C[MN], Lst[MN], stk1[MN], stk2[MN];
    	for (int i = 1; i <= N; ++i) B[i] = A[i];
    	std::sort(B + 1, B + N + 1);
    	int M = std::unique(B + 1, B + N + 1) - B - 1;
    	for (int i = 1; i <= N; ++i)
    		C[i] = std::lower_bound(B + 1, B + M + 1, A[i]) - B;
    	for (int i = 1; i <= M; ++i) Lst[i] = 0;
    	int MinL = 1, tp1 = 0, tp2 = 0;
    	Build(1, 1, N);
    	for (int i = 1; i <= N; ++i) {
    		MinL = std::max(MinL, Lst[C[i]] + 1);
    		Lst[C[i]] = i;
    		for (; tp1 && A[stk1[tp1]] <= A[i]; --tp1)
    			Mdf(1, 1, N, stk1[tp1 - 1] + 1, stk1[tp1], A[i] - A[stk1[tp1]]);
    		for (; tp2 && A[stk2[tp2]] >= A[i]; --tp2)
    			Mdf(1, 1, N, stk2[tp2 - 1] + 1, stk2[tp2], A[stk2[tp2]] - A[i]);
    		stk1[++tp1] = stk2[++tp2] = i;
    		Mdf(1, 1, N, i, i, i);
    		int lpos = Qur(1, 1, N, MinL, i, K + i);
    		if (~lpos && MaxLen < i - lpos + 1) {
    			MaxLen = i - lpos + 1;
    			Ans = lpos + offset;
    		}
    	}
    }
    
    int N, K, D;
    int A[MN], R[MN], B[MN], t;
    
    int main() {
    	scanf("%d%d%d", &N, &K, &D);
    	for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
    	if (D == 0) {
    		int mxl = 1, lst = A[1], len = 1, ans = 1;
    		for (int i = 2; i <= N; ++i) {
    			if (A[i] == lst) ++len;
    			else len = 1, lst = A[i];
    			if (len > mxl) mxl = len, ans = i - mxl + 1;
    		}
    		printf("%d %d
    ", ans, ans + mxl - 1);
    		return 0;
    	}
    	for (int i = 1; i <= N; ++i) R[i] = (A[i] % D + D) % D;
    	for (int i = 1; i <= N; ++i) {
    		B[++t] = (A[i] - R[i]) / D;
    		if (i == N || R[i] != R[i + 1])
    			Solve(B, t, K, i - t), t = 0;
    	}
    	printf("%d %d
    ", Ans, Ans + MaxLen - 1);
    	return 0;
    }
    
  • 相关阅读:
    idea 连接 hive
    css img自适应
    测试视频文件
    ubuntu不显示ipv4地址的解决办法
    nginx path捕获
    union all两个结果集报ORA-12704: character set mismatch错误
    润乾报表试用指南
    报表工具对比之润乾报表与锐浪报表对比
    项目微管理36
    docker远程调用
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/CF407E.html
Copyright © 2020-2023  润新知