Codeforces 1067E Range Deleting
题目链接
https://codeforces.com/contest/1167/problem/E
题目大意
给你一个长度为 $n$ 的数列 $a$ ,保证对于所有 $1 \leq i \leq n$ 有 $a_i \leq x$ 成立,定义 $f(l, r)$ 为删除所有满足 $l \le a_i \le r$ 的数之后所剩下的数列。问使得这个数列为不下降序列的 $l, r$ 共有多少对。
题目分析
考虑如果令 $l = l_0$ ,那么一定可以确定一个最小的 $r_0$ 使得 $f(l_0, r_0)$ 满足题意,对于所有的 $r \geq r_0$ 都满足题意。此时如果将 $l$ 变为 $l_0 + 1$ ,如果能保证前 $l$ 个数满足题意,那么显然 $r_0$ 一定是不移动或者向右移动,只需要向右移动直到不冲突即可。对于 $l = 1$ 时,显然从后往前扫即可确定出第一个 $r$,依次向后扫即可。注意考虑数列中没有出现的数。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> using namespace std; const int maxn = 1e6 + 5; int n, m, t; int a[maxn]; int f[maxn][2]; int read(){ int x; scanf("%d", &x); return x; } int main(){ int i, j; int l, r = 2; int minx = 0x3f3f3f3f, maxx = 0; long long ans = 0; n = read(); m = read(); for(i=1;i<=n;i++){ a[i] = read(); if(!f[a[i]][0]){ f[a[i]][0] = f[a[i]][1] = i; }else{ f[a[i]][1] = i; } } for(i=m;i>0;i--){ if(f[i][0]){ if(f[i][1] < minx){ minx = f[i][0]; }else{ r = i + 1; break; } } } ans += m - r + 2; l = r; for(i=1;i<m;i++){ if(!f[i][0]){ l = max(l, i + 2); ans += m - l + 2; continue; } if(f[i][0] > maxx){ maxx = f[i][1]; r = max(r, i + 1); while(r <= m){ if(f[r][0]){ if(f[r][0] < maxx){ l = r + 1; }else{ break; } } r++; } l = max(l, i + 2); ans += m - l + 2; }else{ break; } } printf("%lld\n", ans); return 0; }