CF1175F The Number of Subpermutations

时间:2021-08-10
本文章向大家介绍CF1175F The Number of Subpermutations,主要包括CF1175F The Number of Subpermutations使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Link

Solution

考虑在什么条件下子区间 \([l,r]\)\(1 到 r - l + 1\) 的排列,

  1. \([l,r]\) 中没有重复的数字

  2. \([l,r]\) 中最大值为 \(r - l + 1\)

于是可以分治,每次考虑在 \([l,r]\) 中且经过 \(mid\) 的子区间,其中 \(mid\)\([l,r]\) 中最大值的位置,那么这些区间的最大值就是 \(a_{mid}\) 了,接下来考虑第一个条件。

可以记录下每个数上一次出现的位置 \(pre\),然后只需要判断区间中最大的 \(pre\) 是否大于区间左端点。

其实可以判断 \(pre\) 的前缀最大值,因为在左端点前的 \(pre\) 一定是小与左端点的。

注意在枚举区间的时候要判断 \(mid\) 左右哪边小,枚举小的那边作为区间的一端,因为区间长度一定是 \(a_{mid}\),所以另一端就确定了,不然可能会被卡成 \(O(n^2)\)

Code

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int N = 3e5 + 5;
int n, a[N];
int pre[N], lst[N];
int st[N][20], f[N];
int ans;

void ST()
{
	for(int i = 1; i <= n; i++)
		st[i][0] = i;
	int lg = log2(n);
	for(int j = 1; j <= lg; j++)
		for(int i = 1; i + (1 << j) - 1 <= n; i++)
			st[i][j] = a[st[i][j - 1]] >= a[st[i + (1 << (j - 1))][j - 1]] ? st[i][j - 1] : st[i + (1 << (j - 1))][j - 1];
}

int qry(int l, int r)
{
	int lg = log2(r - l + 1);
	return a[st[l][lg]] >= a[st[r - (1 << lg) + 1][lg]] ? st[l][lg] : st[r - (1 << lg) + 1][lg];
}

void solve(int l, int r)
{
	if(l > r) return;
	if(l == r)
	{
		if(a[l] == 1) ans++;
		return;
	}
	int mid = qry(l, r);
	if(mid - l + 1 <= r - mid)
	{
		for(int i = l ; i <= mid; i++)
		{
			int j = i + a[mid] - 1;
			if(j >= mid && j <= r && f[j] < i) ans++;
		}
	}
	else
	{
		for(int j = mid; j <= r; j++)
		{
			int i = j - a[mid] + 1;
			if(i <= mid && i >= l && f[j] < i) ans++;
		}
	}
	solve(l, mid - 1);
	solve(mid + 1, r);
	return;
}

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]), pre[i] = lst[a[i]], lst[a[i]] = i;
	ST();
	for(int i = 1; i <= n; i++)
		f[i] = max(f[i - 1], pre[i]);
	solve(1, n);
	printf("%d\n", ans);
	return 0;
}

原文地址:https://www.cnblogs.com/Acestar/p/15122979.html