Educational Codeforces Round 95 (Rated for Div. 2) G. Three Occurrences

PHarr發表於2024-10-03

首先我們隨機兩個陣列\(valA_x,valB_x\)

對於陣列\(a\),記\(cnt\)表示\(a_i\) 在字首中出現的次數。

  1. \(cnt\equiv 0 \mod 3\),則\(b_i=valA_x\)
  2. \(cnt\equiv 1 \mod 3\),則\(b_i=valB_x\)
  3. \(cnt\equiv 2 \mod 3\),則\(b_i=valA_x \oplus valB_x\)

\(pre_i\)表示\(b\)的字首異或和,如果區間\([l.r]\)內每個數的出現次數都是\(3\)的倍數,則滿足\(pre_r \oplus pre_{l-1} = 0\)

再用雙指標求出\([l,r]\)表示對\(r\)來說的最大區間滿足區間內任何一個數出現的次數都不超過3次。此時只要求出滿足\(l\le pos\le r \and pre_r \oplus pre_{pos-1}\)\(pos\)的個數,即可求出\(r\)對答案產生的貢獻。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;


#define int i64

using vi = vector<int>;
using pii = pair<int,int>;

i32 main(){
	ios::sync_with_stdio(false), cin.tie(nullptr);
	mt19937_64 rd(time(0));

	int n;
	cin >> n;
	vi valA(n + 1), valB(n + 1);
	for(int i = 1; i <= n; i ++)
		valA[i] = rd(), valB[i] = rd();

	vi cnt(n + 1), a(n + 1), b(n + 1), pre(n + 1);
	for(int i = 1; i <= n; i ++) {
		cin >> a[i];
		cnt[a[i]] ++;
		if(cnt[a[i]] % 3 == 0) b[i] = valA[a[i]];
		if(cnt[a[i]] % 3 == 1) b[i] = valB[a[i]];
		if(cnt[a[i]] % 3 == 2) b[i] = valA[a[i]] ^ valB[a[i]];
		pre[i] = pre[i - 1] ^ b[i];
	}

	cnt = vi(n + 1);
	map<i64,i32> sum;
	sum[0] = 1;
	int res = 0;
	for(int l = 0 , r = 1; r <= n; r ++) {
		cnt[a[r]] ++;
		while(cnt[a[r]] > 3) {
			cnt[a[l]] --;
			if(l > 0) sum[pre[l - 1]] --;
			l ++;
		}
		res += sum[pre[r]], sum[pre[r]] ++;
	}
	cout << res << "\n";
	return 0;
}

相關文章