题目传送门:CF407E

题意简述:

给定非负整数 \(k,d\) 和一个长度为 \(n\)(\(1\le n\le 2\times 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]\}+l\le k+r\) 且 \(a[l:r]\) 中无重复元素。

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

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

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

下面是代码,时间复杂度 \(\mathcal{O}(n\log 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\n", 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\n", Ans, Ans + MaxLen - 1);
return 0;
}

CodeForces 407E: k-d-sequence的更多相关文章

  1. Codeforces 486E LIS of Sequence(线段树+LIS)

    题目链接:Codeforces 486E LIS of Sequence 题目大意:给定一个数组.如今要确定每一个位置上的数属于哪一种类型. 解题思路:先求出每一个位置选的情况下的最长LIS,由于開始 ...

  2. Codeforces GYM 100114 C. Sequence 打表

    C. Sequence Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description ...

  3. CodeForces 670E Correct Bracket Sequence Editor(list和迭代器函数模拟)

    E. Correct Bracket Sequence Editor time limit per test 2 seconds memory limit per test 256 megabytes ...

  4. Codeforces gym102152 K.Subarrays OR

    传送:http://codeforces.com/gym/102152/problem/K 题意:给定$n(n\le10^5)$个数$a_i(a_i\le10^9)$,对于任一个子数组中的数进行或操作 ...

  5. Codeforces 670E - Correct Bracket Sequence Editor - [线段树]

    题目链接:https://codeforces.com/contest/670/problem/E 题意: 给出一个已经匹配的括号串,给出起始的光标位置(光标总是指向某个括号). 有如下操作: 1.往 ...

  6. 【codeforces 623E】 Transforming Sequence

    http://codeforces.com/problemset/problem/623/E (题目链接) 题意 长度为${n}$的满足前缀按位或为单调递增的${k}$位序列.要求每个位置为${[1, ...

  7. codeforces 1133E K Balanced Teams

    题目链接:http://codeforces.com/contest/1133/problem/E 题目大意: 在n个人中找到k个队伍.每个队伍必须满足最大值减最小值不超过5.求满足条件k个队伍人数的 ...

  8. codeforces C. Cows and Sequence 解题报告

    题目链接:http://codeforces.com/problemset/problem/284/C 题目意思:给出3种操作:t = 1:在前 a 个数中每个数都加上x: t= 2:在数组末尾增加一 ...

  9. 【codeforces 602D】Lipshitz Sequence

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  10. Codeforces 1133E - K Balanced Teams - [DP]

    题目链接:https://codeforces.com/contest/1133/problem/C 题意: 给出 $n$ 个数,选取其中若干个数分别组成 $k$ 组,要求每组内最大值与最小值的差值不 ...

随机推荐

  1. js实现一键复制

    方法一: 使用插件 引入clipboard.js 使用如下 <script> copyFn = function() { var clipboard = new Clipboard('.c ...

  2. java ++和--

    public class Sample { public static void main(String[] args) { , num2 = ; , num4 = ; System.out.prin ...

  3. 去掉DataGridView最后一行的空白行,删除空白行

    //不显示出dataGridView1的最后一行空白   dataGridView1.AllowUserToAddRows = false;       直接在LODE事件

  4. Adams宏导出

    var set var=ip integer_value=1 var set var=macro_name str="" for variable_name=the_macro o ...

  5. 关于DataTable内部索引已损坏的问题 System.Data.RBTree

    1.错误提示: 最近,Winform程序在极其偶然的情况下会遇到如下错误提示 Framework 版本: v4.0.30319 说明: 由于未经处理的异常,进程终止. 异常信息: System.Inv ...

  6. 在开发中进入一个方法后想要到原来那行 ctrl+alt+左 回到上一步 ctrl+alt+右 回到下一步

    在开发中进入一个方法后想要到原来那行 ctrl+alt+左 回到上一步ctrl+alt+右 回到下一步

  7. why’s kafka so fast

    As we all know that Kafka is very fast, much faster than most of its competitors. So what’s the reas ...

  8. Task 小记

    1. 注意 Task 执行的顺序. 如下代码: IQueryable<T> querySet; if (preConditionExpression == null) { querySet ...

  9. 【03】Python:分支和循环

    写在前面的话 在写代码的时候,我们的代码不可能总是一行一行语句的堆叠,有些时候我们需要对一个事物进行判断,或者很大一组数据需要循环挨个处理.这些不可能让我们一步一步的去写.所以有了接下来的分支结构和循 ...

  10. ElementUI如何展开指定Tree树节点

    原文:https://blog.csdn.net/gaojie_csdn/article/details/80738488 [问题] 在页面使用ElementUI的时候,想做出一个主动展开树节点的效果 ...