1. 程式人生 > 其它 >[Byte OI] CSP-S 模擬賽題解

[Byte OI] CSP-S 模擬賽題解

[Byte OI] 佳餚

這道題的部分分只要先離散化,然後暴力就行了。

可能有一些同學是會莫隊的,這道題用莫隊做其實挺簡單的,但莫隊是離線演算法(於是我加了一個強制線上)。

其實一般的莫隊都是可以強制線上化改造成分塊的。

而且這道題的空間給了 \(512 MB\),這就說明我們可以自由的定義陣列,用空間換時間。

首先我們將數列分塊。

我們設 \(F_{i,j}\) 為從第 \(i\) 個塊到第 \(j\) 個塊的答案。

\(sum_{i,x}\) 為前 \(i\) 個塊中數字 \(x\) 的出現的總次數。

對於每一個查詢 \(l \sim r\)

如果 \(l\)\(r\) 在一個塊內,暴力列舉即可,時間複雜度 \(\Theta(n)\)

如果 \(l\)\(r\) 在不同的塊內,則我們可以用 \(F\) 陣列得出 \(l \sim r\) 之間整塊的答案,時間複雜度 \(\Theta(n)\)

接著考慮統計旁邊零散塊的答案,

我們可以用 \(sum\) 陣列得出零散塊中每一個數字的出現次數,

於是我們暴力統計即可。

總時間複雜度 \(\Theta(m \sqrt{n})\),空間複雜度 \(\Theta(n \sqrt{n})\)

CODE TIME

#include <bits/stdc++.h>
using namespace std;
int n, m, a[300010], d[300010], siz, bnum, lastans = 0;
int F[550][550], cnt[300010], sum[550][300010], L[550], R[550], belong[300010];
inline int price(int x) {
	if (x < 2) return 0;
	else if (x == 2) return 1;
	else return -1;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i], d[i] = a[i];
	sort(d + 1, d + n + 1); int M = unique(d + 1, d + n + 1) - d - 1;
	for (int i = 1; i <= n; i++) a[i] = lower_bound(d + 1, d + M + 1, a[i]) - d;
	siz = sqrt(n); bnum = (n - 1) / siz + 1;
	for (int i = 1; i <= bnum; i++) {
		L[i] = (i - 1) * siz + 1; R[i] = min(i * siz, n);
		for (int j = 1; j <= M; j++) sum[i][j] = sum[i - 1][j];
		for (int j = L[i]; j <= R[i]; j++) {
			belong[j] = i;
			sum[i][a[j]]++;
		}
	}
	for (int i = 1; i <= bnum; i++) {
		for (int j = 1; j <= M; j++) cnt[j] = 0;
		int Ans = 0;
		for (int j = i; j <= bnum; j++) {
			for (int k = L[j]; k <= R[j]; k++) {
				cnt[a[k]]++;
				Ans += price(cnt[a[k]]) - price(cnt[a[k]] - 1);
			}
			F[i][j] = Ans;
		}
	}
	for (int i = 1; i <= M; i++) cnt[i] = 0;
	for (int i = 1; i <= m; i++) {
		int l, r; cin >> l >> r;
		l = l ^ abs(lastans);
		r = r ^ abs(lastans);
		if (l > r) swap(l, r);
		l = max(1, l); l = min(l, n);
		r = max(1, r); r = min(n, r);
		if (belong[r] - belong[l] <= 1) {
			int Ans = 0;
			for (int j = l; j <= r; j++) {
				cnt[a[j]]++;
				Ans += price(cnt[a[j]]) - price(cnt[a[j]] - 1);
			}
			cout << Ans << endl; lastans = Ans;
			for (int j = l; j <= r; j++) cnt[a[j]]--;
		}
		else {
			int Ans = F[belong[l] + 1][belong[r] - 1];
			for (int j = l; j <= R[belong[l]]; j++) {
				cnt[a[j]]++;
				Ans += price(cnt[a[j]] + sum[belong[r] - 1][a[j]] - sum[belong[l]][a[j]]);
				Ans -= price(cnt[a[j]] + sum[belong[r] - 1][a[j]] - sum[belong[l]][a[j]] - 1);
			}
			for (int j = L[belong[r]]; j <= r; j++) {
				cnt[a[j]]++;
				Ans += price(cnt[a[j]] + sum[belong[r] - 1][a[j]] - sum[belong[l]][a[j]]);
				Ans -= price(cnt[a[j]] + sum[belong[r] - 1][a[j]] - sum[belong[l]][a[j]] - 1);
			}
			for (int j = l; j <= R[belong[l]]; j++) cnt[a[j]]--;
			for (int j = L[belong[r]]; j <= r; j++) cnt[a[j]]--;
			cout << Ans << endl;
			lastans = Ans;
		}
	}
	return 0;
}