牛客小白月赛122 E

https://ac.nowcoder.com/acm/contest/119664

E

计算f(l,r)需要判断[l,r]是否为[1,l-1]+[r+1,n]的子序列(对此我们可以用双指针实现);
如果每次枚举(l,r)时都去判断一次,得到时间复杂度为O(n3*logn)对于n=2000不够;
我们考虑如何预处理以达到快速判断的目的;

方法一

分析

显然对于一个确定的l,若r满足条件,那么显然r-1也满足条件。我们可以通过枚举l,然后从大到小枚举r,找到rmax,那么比r小的都不必进行双指针判断。

更进一步,对于符合条件的(l,r),l增加时,rmax不增;可以进一步减小枚举量 时间复杂度O(n2

代码实现

#include <bits/stdc++.h>
using namespace std;
int n;
int P[10000];
bool check (int l, int r)//返回f(i,j)的值
{
	int x = l;
	for (int i = 1; i <= n; i++)
	{
		if (i == l)
		{
			i = r;
			continue;
		}
		if (x <= r && P[x] == P[i])
		{
			x++;
		}
	}
	return x == r + 1;
};
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> P[i];
	}
	int ans = 0;
	for (int i = 2; i < n; i++)//枚举l
	{
		int l = i - 1, r = n - 1;
		while (l < r)//二分查找最大的r
		{
			int mid = (l + r + 1) >> 1;
			if (check(i, mid))
			{
				l = mid;
			}
			else
			{
				r = mid - 1;
			}
		}
		ans += l - i + 1;
	}
	cout << ans << endl;

	return 0;
}

方法二

分析

考虑 ll[i] 和 rr[i] :
ll[i] 是满足[i,i+x-1]是[1,i-1]的子序列的x的最大值
rr[i] 是满足[i-x+1,i]是[i+1,n]的子序列的x的最大值

那么f(i,j)==1等价于ll[l]+rr[r]>r-l;
时间复杂度O(n2

代码实现

#include<bits/stdc++.h>
using namespace std;
int p[10000], ll[10000], rr[10000];
int n;
bool check1(int i, int x) //起点 长度
{
	int k = i;
	int t = 1;
	while (t <= i - 1 )
	{
		if (p[k] == p[t])
		{
			k++;
			if (k == i + x)
				return 1;
		}
		t++;
		
	}
	return 0;
}
bool check2(int i, int x) //终点 长度
{
	int k = i - x + 1;
	int t = i + 1;
	while (t <= n)
	{
		if (p[k] == p[t])
		{
			k++;
			if (k == i + 1)
				return 1;
		}
		t++;
	}
	return 0;
}
int main()
{
	
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> p[i];
	for (int i = 2; i < n; i++)
	{
		int l = 0, r = n;
		int mid;
		while (r - l >= 0)
		{
			if (r == l)
			{
				ll[i] = l;
				break;
			}
			mid = (l + r + 1) / 2;
			if (check1(i, mid))
				l = mid;
			else
				r = mid-1;
		}
	}
	for (int i = 2; i < n; i++)
	{
		int l = 0, r = n;
		int mid;
		while (r - l >= 0)
		{
			if (r == l)
			{
				rr[i] = l;
				break;
			}
			mid = (l + r + 1) / 2;
			if (check2(i, mid))
				l = mid;
			else
				r = mid-1;
		}
	}
	int sum = 0;
	for (int l = 2; l < n; l++)
		for (int r = l; r < n; r++)
			if (ll[l] + rr[r] >= r - l+1)
				sum++;
	cout << sum;
	return 0;
}
posted @ 2025-10-18 11:24  Ahui2667d  阅读(14)  评论(0)    收藏  举报