1. 程式人生 > >4245: [ONTAK2015]OR-XOR

4245: [ONTAK2015]OR-XOR

using 不能 最小 價值 預處理 一位 () 這一 bits

4245: [ONTAK2015]OR-XOR

https://www.lydsy.com/JudgeOnline/problem.php?id=4245

 1 /*
 2 要求分成m份,總價值為a1|a2|a3...,總價值最小,ai為第i份的異或和。
 3  
 4 首先預處理異或和。 
 5 根據貪心的思想,高位最好是0。
 6 於是從高位往低位枚舉,看一下每一位是否可以為0。
 7 如果當前這一位可以為0,每一份的(異或和)(或)起來都是0,所以每一份異或和的這一位不能有1
 8 那麽一個點可以成為分割點當且僅當這個點的sum值的這一位為0,然後統計有多少個點的sum為0
9 如果個數>=m且這一位上的所有1為偶數個(sum[n]&(1LL<<i)==0),那麽這一位可以為0,然後對於那些不能成為分割點的點,標記不能再成為分割點。 10 不然會使這一位不為0了。 11 如果不能0,那就為1了,ans更新。 12 */ 13 #include<bits/stdc++.h> 14 using namespace std; 15 typedef long long LL; 16 17 inline LL read() { 18 LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if
(ch==-)f=-1; 19 for (;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f; 20 } 21 22 const int N = 500100; 23 LL a[N],sum[N],flag[N]; 24 25 int main() { 26 int n,m;cin >> n >> m; 27 for (int i=1; i<=n; ++i) 28 a[i] = read(),sum[i] = sum[i-1] ^ a[i]; 29 LL ans = 0
; 30 for (int i=62; i>=0; --i) { // 看第i位能否為0 31 int cnt = 0; 32 for (int j=1; j<=n; ++j) { // 統計有多少個右端點滿足條件 33 if (!flag[j] && (sum[j]&(1LL<<i))==0) cnt++; 34 } 35 if (cnt >= m && (sum[n]&(1LL<<i))==0) { // 如果這一位可以放0。---- 少加了對花括號。。。 36 for (int j=1; j<=n; ++j) // 對所有不可以成為右端點的點打標記 37 if ((sum[j]&(1LL<<i)) != 0) flag[j] = 1; 38 } 39 else ans |= (1LL << i); 40 } 41 cout << ans; 42 return 0; 43 }

4245: [ONTAK2015]OR-XOR