2019HDU多校訓練第二場 Longest Subarray


題意:給你一個串,問滿足以下條件的子串中最長的是多長:對於每個數字,要么在這個子串沒出現過,要么出現次數超過k次。

思路:對於這類問題,常常轉化為數據結構的詢問問題。我們考慮枚舉右端點,對於當前右端點,我們單獨考慮每一種數的合法區間。假設當前枚舉的右端點是i,考慮的數字是c,在右端點左邊離i最近的數字c的位置是p1,離i第k遠的數字c的位置是p2, 容易發現,數字c的合法區間為[1, p2]和[p1 + 1, i],對應的情況是選擇這個數至少k個和不選這個數。那么,如果我們用線段樹來維護覆蓋的區間,對於每一種數的合法區間在線段樹上+1,這樣我們只要找到在i前面值為c的最小的位置就是右端點為i的最優解。由於每次右端點只移動1,所以可以在O(logn)時間內維護一個數合法區間的變化。最小位置的找法可以通過維護區間最大值然后在線段樹上二分即可。

代碼:

#include <bits/stdc++.h>
#define ls (o << 1)
#define rs (o << 1 | 1) 
using namespace std;
const int maxn = 100010;
vector<int> pos[maxn];
int now[maxn];
int n, c, k;
int a[maxn];
struct SegmenTree {
	int mx, lz;
};
SegmenTree tr[maxn * 4];
void pushup(int o) {
	tr[o].mx = max(tr[ls].mx, tr[rs].mx);
}
void pushdown(int o) {
	if(tr[o].lz != 0) {
		tr[ls].mx += tr[o].lz;
		tr[rs].mx += tr[o].lz;
		tr[ls].lz += tr[o].lz;
		tr[rs].lz += tr[o].lz;
		tr[o].lz = 0;
	}
}
void build(int o, int l, int r) {
	tr[o].mx = 0;
	tr[o].lz = 0;
	if(l == r) {
		return;
	}
	int mid = (l + r) >> 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
	pushup(o);
}
void update(int o, int l, int r, int ql, int qr, int val) {
	if(ql > qr) return;
	if(l >= ql && r <= qr) {
		tr[o].lz += val;
		tr[o].mx += val;
		return;
	}
	pushdown(o);
	int mid = (l + r) >> 1;
	if(ql <= mid) update(ls, l, mid, ql, qr, val);
	if(qr > mid) update(rs, mid + 1, r, ql, qr, val);
	pushup(o); 
}
int query(int o, int l, int r) {
	if(l == r) return l;
	int ans = -1, mid = (l + r) >> 1;
	pushdown(o);
	if(tr[ls].mx == c) ans = query(ls, l, mid);
	else if(tr[rs].mx == c) ans = query(rs, mid + 1, r);
	return ans;
}
int main() {
	while(~scanf("%d%d%d", &n, &c, &k)) {
		for (int i = 1; i <= c; i++) {
			pos[i].clear();
			pos[i].push_back(0);
		}
		for (int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
			pos[a[i]].push_back(i);
		}
		build(1, 1, n);
		for (int i = 1; i <= c; i++) {
			pos[i].push_back(n + 1);
			update(1, 1, n, pos[i][0] + 1, pos[i][1] - 1, 1);
			now[i] = 0;
		}
		int ans = 0;
		for (int i = 1; i <= n; i++) {
			int t = a[i];
			update(1, 1, n, pos[t][now[t]] + 1, pos[t][now[t] + 1] - 1, -1);
			if(now[t] >= k) update(1, 1, n, 1, pos[t][now[t] - k + 1], -1);
			now[t]++;
			update(1, 1, n, pos[t][now[t]] + 1, pos[t][now[t] + 1] - 1, 1);
			if(now[t] >= k) update(1, 1, n, 1, pos[t][now[t] - k + 1], 1);
			int tmp = query(1, 1, n);
			if(tmp != -1)
				ans = max(ans, i - tmp + 1);
		}
		printf("%d\n", ans);
	}
} 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM