LOJ10121 与众不同

题目蓝链

Solution

首先要预处理出每一个位置的上一个与当前位置的数相同的位置,然后就可以利用它求出\(pos[i]\),表示以第\(i\)个数为结尾的最长完美序列的起始位置。然后就可以求出每一个位置往前最多可以选多少个数,我们用RMQ来维护一下这个东西

询问的时候,由于\(pos\)单调不降,直接在\([l, r]\)中二分一下找到最靠前的一个位置使得\(pos[mid] > l\),因为要保证选的数要在\([l, r]\)的范围内。所以\(ans = max(mid - l, Max(mid, r))\)\(Max(l, r)\)表示RMQ维护的最大值

Code

#include <bits/stdc++.h>

using namespace std;

#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

inline int read() {
	int sum = 0, fg = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
	return fg * sum;
}

const int maxn = 2e5 + 10;
const int maxm = 2e6 + 10;

int n, m;
int lst[maxm], pos[maxn], f[maxn], Max[maxn][18], Pow[18], Log[maxn];

int find(int l, int r) {
	int L = l; /**/
	while (l <= r) {
		int mid = (l + r) >> 1;
		if (pos[mid] > L) r = mid - 1;
		else l = mid + 1;
	}
	return r + 1;
}

int query(int l, int r) {
	int x = Log[r - l + 1];
	return max(Max[r][x], Max[l + Pow[x] - 1][x]);
}

int main() {
#ifdef xunzhen
	freopen("perfect.in", "r", stdin);
	freopen("perfect.out", "w", stdout);
#endif

	n = read(); m = read();

	Pow[0] = 1;
	for (int i = 1; i <= 17; i++) Pow[i] = Pow[i - 1] << 1;
	for (int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;

	for (int i = 1; i <= n; i++) {
		int k = read() + (int)1e6;
		pos[i] = max(pos[i - 1], lst[k] + 1);
		lst[k] = i;
		f[i] = i - pos[i] + 1;
	}

	for (int i = 1; i <= n; i++) {
		Max[i][0] = f[i];
		for (int j = 1; j <= 17; j++) {
			int pre = max(i - Pow[j - 1], 0); /**/
			Max[i][j] = max(Max[i][j - 1], Max[pre][j - 1]);
		}
	}

	while (m--) {
		int l = read() + 1, r = read() + 1;
		int res = find(l, r), ans = res - l;
		if (res <= r) ans = max(ans, query(res, r));
		printf("%d\n", ans);
	}

	return 0;
}

Summary

这道题是真的坑 其实是我坑...

这道题我不得不承认,还是有一点难度的

RMQ一定要经常打一下,要不然会有很多细节写错

\(debug\):打错的地方已在代码中\(mark\)

posted @ 2018-09-19 09:26  xunzhen  阅读(304)  评论(0)    收藏  举报