Codeforces 1067E Range Deleting

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;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据