http://codeforces.com/problemset/problem/1167/E
题意:
删除一个区间f(l, r)后使剩下的数不递减, 求这样区间的个数
因为一个数可以在这个数组中出现多次,所以转化为,先预处理出所有数的最左边的下标和最右边的下标,这样每个数都有一个区间
然后求最多有多少个f(l, r)使剩下的数的左右区间不相交
解析:
先从后向前求出一个递减的序列,如果当前数r的区间扰乱了这个递减的序列,那么f(1,r)、 f(1, r + 1)······f(1, x)都符合要求 所以就有x - r + 1个
然后我们定r,缩l判断f(2, r)是否符合要求,如果不符合则r向后累加
当然首先要保证1的区间和2的区间,是递增的 如果不递增,输出结果即可,自己想一想为什么
#include <bits/stdc++.h> using namespace std; const int maxn = 1001000, INF = 0x7fffffff; typedef long long LL; LL l[maxn], r[maxn]; LL vis[maxn]; struct node { LL succ; }Node[maxn]; int main() { LL n, x; cin >> n >> x; for(int i = 1; i <= x; i++) l[i] = INF; for(LL i = 1; i <= n; i++) { LL tmp; cin >> tmp; Node[tmp].succ = tmp; vis[tmp] = 1; l[tmp] = min(l[tmp], i); r[tmp] = i; } LL pre, succ; for(int i = 1; i <= x; i++) { if(vis[i] == 0) { if(i == 1) r[i] = 1, succ = i; else r[i] = pre, Node[i].succ = succ; } if(vis[i]) succ = i; pre = r[i]; } for(int i = x; i >= 1; i--) { if(vis[i] == 0) { if(i == x) l[i] = n; else l[i] = pre; } pre = l[i]; } int pos = -1; for(int i = x; i >= 2; i--) { if(r[i - 1] > l[i]) { pos = Node[i - 1].succ; break; } } if(pos == -1) { LL ret = (LL)(x * (x + 1) / 2); printf("%lld ", ret); return 0; } LL res = 0; res += x - pos + 1; // cout << res << endl; for(int i = 1; i <= x; i++) { if(l[i] < r[i - 1] && vis[i] != 0) break; while(pos <= x - 1 && r[i] > l[pos + 1]) pos++; res += x - pos + 1; } cout << res << endl; return 0; }