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 }
bzoj 4245 [ONTAK2015]OR-XOR

然而这题还有更加简单的方法……

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 }$的值最小

依然是逐位贪心就行了……

posted @ 2018-09-14 16:24  KingSann  阅读(155)  评论(0编辑  收藏  举报