T1 [JZOJ6310] Global warming
题目描述
给定整数 $n$ 和 $x$,以及一个大小为 $n$ 的序列 $a$。
你可以选择一个区间 $[l,r]$,然后令 $a[i]+=d \; (l \leq i \leq r)$,其中 $d$ 满足 $|d| \leq x$。
要求最大化 $a$ 的最长上升子序列的长度,并输出该值。
数据范围
对于 $5\%$ 的数据点,$n,x \leq 10$
对于另外 $10\%$ 的数据点,$n,x \leq 50$
对于另外 $13\%$ 的数据点,$n \leq 1000$
对于另外 $10\%$ 的数据点,$x=0$
对于另外 $20\%$ 的数据点,$x \leq 5$,$n \leq 5 \times 10^4$
对于另外 $17\%$ 的数据点,$x=10^9$
对于 $100\%$ 的数据点,$n \leq 2 \times 10^5$,$x \leq 10^9$
分析
$Subtask$ 真是让人头大,玄学挂了两个点结果只得了 $62 \, pts$
这题有几个很显然的地方
令区间 $[l,r] \; (1 \leq l \leq r < n)$ 加上 $i \; (0 \leq i \leq x)$ 必不优于区间 $[l,n]$
令区间 $[l,r] \; (1 < l \leq r \leq n)$ 减去 $i \; (0 \leq i \leq x)$ 必不优于区间 $[1,r]$
令区间 $[l,n]$ 加上 $i \; (0 \leq i < x)$ 或令区间 $[1,r]$ 减去 $i$ 必不优于加上/减去 $x$
由于加减实际上是等价的,所以我们假定让区间 $[1,r] \; (1 \leq r < n)$ 减去 $x$
设 $f_i$ 表示减小的区间为 $[1,i-1]$ 且 $a_i$ 被选中时的最长上升子序列长度
首先正序做一遍最长上升子序列可以处理出 $f$ 数组,然后倒序做一遍找出最优解
若当前位置为 $i$,则 $ans_i=f_i \, +$ 以 $i$ 结尾的最长下降子序列长度(倒序)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define N 200005 int n, x, pos, ans; int a[N], q[N], f[N]; int main() { scanf("%d%d", &n, &x); for (int i = 1; i <= n; i++) scanf("%d", a + i); for (int i = 1; i <= n; i++) { f[i] = lower_bound(q + 1, q + q[0] + 1, a[i]) - q - 1; pos = lower_bound(q + 1, q + q[0] + 1, a[i] - x) - q; q[pos] = a[i] - x; q[0] = max(q[0], pos); } q[0] = 0; for (int i = n; i; i--) { pos = lower_bound(q + 1, q + q[0] + 1, a[i], greater<int>()) - q; q[pos] = a[i]; q[0] = max(q[0], pos); ans = max(ans, f[i] + pos); } printf("%d", ans); return 0; }