給定一個長度爲\(n(1 \le n \le 500000)\)的序列\(a_i(0 \le a_i \le 10^{18})\),將它劃分爲\(m(1 \le m \le n)\)段連續的區間,設第\(i\)段的費用\(c_i\)爲該段內全部數字的異或和,則總費用爲\(c_1 \ or \ c_2 \ or \ ... \ or \ c_m\)。請求出總費用的最小值。c++
這種題就考慮每一位。spa
首先求出前綴和\(s_i\)
貪心地從大位掃向小位,咱們只須要判斷當前位\(i\)可否爲\(0\)便可。
若是當前位能爲0,則表示全部未刪除的前綴和至少有\(m\)個第\(i\)位爲0,並且\(s_n\)第\(i\)位必須是0,而後刪除全部這一位不是1的前綴和。code
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll getint() { ll x=0; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()); for(; c>='0'&&c<='9'; x=x*10+c-'0', c=getchar()); return x; } ll a[500005]; int main() { int n=getint(), m=getint(); for(int i=1; i<=n; ++i) { a[i]=getint(); a[i]^=a[i-1]; } ll ans=0; for(int j=63; ~j; --j) { if((a[n]>>j)&1) { ans|=1ll<<j; continue; } int cnt=0; for(int i=1; i<=n; ++i) { if(a[i]>=0 && !((a[i]>>j)&1)) { ++cnt; } } if(cnt>=m) { for(int i=1; i<=n; ++i) { if(a[i]>=0 && ((a[i]>>j)&1)) { a[i]=-a[i]; } } } else { ans|=1ll<<j; } } printf("%lld\n", ans); return 0; }