[Ybt High-Efficiency Advanced 4-3-3] [LOJ 10121] Out of the ordinary

Out of the ordinary

Topic link: ybt high-efficiency advanced 4-3-3 / LOJ 10121

General idea

Give you a sequence of numbers, and then ask for an interval each time, asking you to find a sub-interval with the largest length in it, so that there are no repeated numbers in this sub-interval.

Ideas

We consider first finding one side as the right endpoint of the interval, and which one can be the leftmost endpoint.
The dp equation can be derived: fi = max ⁡ (fi − 1, lastai + 1) f_i=\max(f_{i-1},last_{a_i}+1)fi=max(fi1,lastai+1)
l a s t a i last_{a_i} lastaiShi- ai a_iai(The number in the interval) where did it appear for the last time before, if it didn’t appear before, it’s 0 00 , this can be maintained)

Then you can find fi f_ifi, And then by the way find the longest length of the interval with it as the right end point. (That is right minus the leftmost + 1 +1+1

Then we consider how to find the smallest among all its subintervals.
Then we must first discover a property: fi f_ifi The sequence is not descending.

Then we want to violently enumerate the right endpoint of the subrange first, and then there will be the front left endpoint.
Then if the left endpoint is on the left of the given interval, then the left interval cannot be selected that far, and the farthest can only be the left endpoint of the given interval.
If it is not, you can choose it directly.

According to what we found before, we don't talk about the sequence, there should be a demarcation point, so that the left end that is the farthest right end will be over, but the right end will not.
Then we will discuss separately.

For the left, their left endpoints are the same (given the left endpoint of the interval), then we have to make the right endpoint the longest, that is, the last one before the dividing point.
For the right side, their right end point and the corresponding leftmost end point are both in a given interval, then we take a maximum value for the longest length obtained above.

Then we consider how to optimize the maximum value on the right.
Because the number will not change (it has nothing to do with the left and right endpoints of the given interval, it only needs to be on the right side of the dividing point of this interval), and to find the extreme value of the interval, we consider using the ST table.

As for how to find the demarcation point, we can find it by dichotomy based on its monotonicity (not decreasing).

Then the problem is solved.

Code

#include<cstdio>
#include<iostream>
#define di 1000000

using namespace std;

int n, m, a[200001], last[2000001];
int pre[200001], f[200001][21], x, y, log[200001];

void get_log() {
    
    //预处理 log
	int now = 1, x = 0;
	while ((now << 1) < 200000) {
    
    
		for (int i = now; i < (now << 1); i++)
			log[i] = x;
		x++;
		now <<= 1;
	}
	while (now <= 200000) log[now++] = x;
}

int main() {
    
    
	get_log();
	
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
    
    
		scanf("%d", &a[i]);
		pre[i] = max(pre[i - 1], last[a[i] + di] + 1);//以它为右边左端点最左是哪里
		f[i][0] = i - pre[i] + 1;//上面的左端点和右端点组成序列的长度
		last[a[i] + di] = i;//维护这个数上次出现的位置
	}
	
	for (int i = 1; i <= log[n]; i++)//ST 表合并
		for (int j = 1; j <= n; j++)
			if (j + (1 << (i - 1)) > n) f[j][i] = f[j][i - 1];
				else f[j][i] = max(f[j][i - 1], f[j + (1 << (i - 1))][i - 1]);
	
	for (int i = 1; i <= m; i++) {
    
    
		scanf("%d %d", &x, &y);
		x++;
		y++;
		
		int l = x, r = y, ans = x - 1;//二分出分界点
		while (l <= r) {
    
    
			int mid = (l + r) >> 1;
			if (pre[mid] < x) ans = mid, l = mid + 1;
				else r = mid - 1;
		}
		
		if (ans >= y) {
    
    //全部都是分界点左边
			printf("%d\n", ans - x + 1);
			continue;
		}
		int size = log[y - (ans + 1) + 1];//分界点左边直接选最右的长度最大,分界点右边的用 ST 表求最大值
		printf("%d\n", max(ans - x + 1, max(f[ans + 1][size], f[y - (1 << size) + 1][size])));
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/115027147