bzoj 4245 [ONTAK2015]OR-XOR
给定一个长度为 $n$ 的序列 $a_1,a_2, \dots, a_n$,请将它划分为 $m$ 段连续的区间,设第 $i$ 段的费用 $c_i$ 为该段内所有数字的异或和,则总费用为 $c_1 \text{ or } c_2 \text{ or } \dots \text{ or } c_m$
请求出总费用的最小值
$1 \le m \le n \le 5 \times 10^5$
$0 \le a_i \le 10^{18}$
一道套路小水题
既然只有 $\text{or}$ 和 $\text{xor}$ 参与运算,那么思路大体是逐位考虑了
考虑每一位对答案的贡献,异或相当于二进制下不进位加法,或相当于如果某个块中的 $1$ 的个数为奇数,那么贡献为 $1$,也就是说如果总共有奇数个 $1$ 那么贡献一定为 $1$
否则的话从高位往低位依次贪心即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 500000 + 10; 5 int n, m, b[N]; ll a[N], ans; 6 7 template<typename T> inline void read(T &x) { 8 char c = x = 0; 9 while(!isdigit(c)) c = getchar(); 10 while(isdigit(c)) x = x * 10 + c - '0', c = getchar(); 11 } 12 13 struct T { int nxt[N]; } t[2]; 14 15 void sol(int bit) { 16 int cnt = 0; 17 for(int i = 1 ; i <= n ; ++ i) if(b[i] = ((a[i] >> bit) & 1)) ++ cnt; 18 if(cnt & 1) { ans |= 1ll << bit; return ; } 19 t[1] = t[0]; 20 for(int i = 1 ; i <= n ; ++ i) b[i] += b[i - 1]; 21 for(int i = 1 ; i <= n ; ) { 22 int ql = i, qr = t[0].nxt[i]; 23 if((b[qr] - b[ql - 1]) & 1) { 24 int j = qr + 1; 25 while(j <= n) { 26 int tl = j, tr = t[0].nxt[j]; 27 t[0].nxt[i] = t[0].nxt[j]; 28 if((b[tr] - b[tl - 1]) & 1) { 29 break; 30 } 31 j = tr + 1; 32 } 33 i = j; 34 } else { 35 i = qr + 1; 36 } 37 38 } 39 int tot = 0; 40 for(int i = 1 ; i <= n ; i = t[0].nxt[i] + 1) { 41 ++ tot; 42 } 43 if(tot < m) { 44 ans |= 1ll << bit; 45 t[0] = t[1]; 46 } 47 } 48 49 int main() { 50 read(n), read(m); 51 for(int i = 1 ; i <= n ; ++ i) read(a[i]), t[0].nxt[i] = i; 52 53 for(int bit = 60 ; ~ bit ; -- bit) { 54 sol(bit); 55 } 56 printf("%lld\n", ans); 57 }
然而这题还有更加简单的方法……
SFN1036 bzoj 4245: [ONTAK2015]OR-XOR
$$(a \text{ xor } b) \text{ or } b=a \text{ or } b$$
证明?
由于这两种位运算可以逐位考虑,因此只需要考虑 $a,b \in \{0,1\}$ 即可
如果 $b=1$,则等式显然为 $1=1$ 的形式,于是只需要考虑 $b=0$ 的情况
于是就转化为了证明 $a \text{ xor } 0 = a$
由于 $\text{xor}$ 的意义为二进制下不进位加法,因此 $a \text { xor } 0 = a$
于是证毕
然后有(这里的$n$和上面的$n$意思不同)
$$\begin{aligned} &s_1 \text{ or } (s_1 \text{ xor } s_2) \text{ or } (s_2 \text{ xor } s_3) \dots \text{ or } (s_{n-1} \text{ xor } s_n) \\ =&(s_2 \text{ xor } s_1) \text{ or }s_1 \text{ or } (s_2 \text{ xor } s_3) \dots \text{ or } (s_{n-1} \text{ xor } s_n) \\ =&s_2 \text{ or }s_1 \text{ or } (s_2 \text{ xor } s_3) \dots \text{ or } (s_{n-1} \text{ xor } s_n) \\ =&s_1 \text{ or } s_2 \text{ or } (s_2 \text{ xor } s_3) \dots \text{ or } (s_{n-1} \text{ xor } s_n) \\ =&s_1 \text{ or } s_2 \text{ or } s_3 \text{ or } (s_3 \text{ xor } s_4) \dots \text{ or } (s_{n-1} \text{ xor } s_n) \\ =&s_1 \text{ or } s_2 \text{ or } s_3 \dots \text{ or } s_n \end{aligned}$$
于是问题就转化为了把一个异或前缀和序列中选若干个元素,使得$\text{ or }$的值最小
依然是逐位贪心就行了……