1. 程式人生 > 其它 >Codeforces Round #746 (Div.2) 題解

Codeforces Round #746 (Div.2) 題解

標籤 :題解


1592A - Геймер Хемосе


1592B - Hemose Shopping

我們發現,在這個陣列中,左右兩部分是可以任意交換的。

如 :\(x = 5\), 有陣列 \([7, 1, 5, 4, 3, 2, 6]\), 發現完全可以排列成\([1, 2, 5, 4, 3, 6, 7]\)

證 :\(a[i]\)\(a[i + d](d < x)\), 可以通過 $ a[i + d + x] $ 實現交換,故$ [1, n - x] \cup [x + 1, n]$ 可以相當於 \(sort\)。剩下的沒辦法,動都動不了,只能判斷是否不降, 若不降就是 \(\text{YES}\)

, 否則 \(\text{NO}\)


1592C - Bakry and Partitioning

提一嘴 :聯通塊數是\(2 \sim k\),不是強制 \(k\)

可以發現,要麼兩個聯通塊, 要麼三個聯通塊,其他的情況都等價於這兩種情況。

  1. 分為兩個聯通塊, \(\bigoplus allsum = 0\) 隨便刪一條邊即可。
  2. 發現 \(\bigoplus allsum = \bigoplus everyblocksum\), \(dfs\) 一遍找子樹 \(\bigoplus sum = \bigoplus allsum\), 統計一下,個數大於等於2即可。
    注意:已經等於\(\bigoplus allsum\)
    的要割掉,即返回 \(0\)

1592E - Скучающий Бакри

易知,應該在每一位上考慮。

結論 :當一段區間有貢獻,當且僅當這一段區間全為 \(1\)。證明易知。

以此結論,我們考慮每個區間 \([l, r]\) 模擬兩數 \(xorsum, andsum\) 二進位制位比較的過程:從高到低,某一位 \(1>0\)

當我們比較到第 \(k\) 位時,我們所比較的 \(andsum = 1\) 時,\(xorsum\) 必然為 \(0\), 故第 \(1\)\(k - 1\) 位的 \(xorsum\)\(andsum\) 均為 \(0\)

故統計當前異或和,當此時\(x\)

異或和 \(\bigoplus_{begin} ^{x}\) 在以前出現過\(\bigoplus_{begin} ^{y}\)時,這一段的異或和\(\bigoplus_{y + 1} ^{x}\)\(0\),故統計當前答案 \(x- y\) 即可。


#include <bits/stdc++.h>
using namespace std;
int read() {
	int f = 1, x = 0; char c = getchar();
	while(!isdigit(c)) {if(c == '-') f = -f; c = getchar();}
	while(isdigit(c)) {x = (x << 1) + (x << 3) + c - '0'; c = getchar();}
	return x * f;
}
const int N = 1e6 + 5;
int n, m, p, q, ans, a[N];
unordered_map <int, int> mp;
int main() {
	n = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 20, sum = 0, tmp; i >= 0; sum = 0, i --) {
		mp.clear(), mp[0] = 1;
		for(int j = 1; j <= n; j ++) {
//			cout << int((a[j] >> i) & 1) << " " ;
			if(!((a[j] >> i) & 1)) {
				sum = 0; mp.clear(); mp[0] = j + 1;
				continue;
			} 
			sum ^= a[j]; tmp = (sum >> i) << i;
			if(!mp[tmp]) 
				mp[tmp] = j + 1;
			else 
				ans = max(ans, j - mp[tmp] + 1);
		}
//		cout << "\n";
	}
	cout << ans;
	return 0;
}