来自FallDream的博客,未经允许,请勿转载,谢谢。
给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ... or c[m]。请求出总费用的最小值。
n<=500000 ai<=10^18
考虑从大到小贪心每一位能否取0,从前往后只要能成那一位是0的段就分段,能分完并且段数大等于m的时候可以取,并用分成的那么多段当成新的序列继续做,不然这一位就取1.
#include<iostream>
#include<cstdio> #define ll long long #define MN 500000 using namespace std; inline ll read() { ll x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,top=0,now=1; ll a[65][MN+5],ans=0; int main() { n=read();m=read(); for(int i=1;i<=n;++i) a[now][i]=read(); for(int j=60;~j;--j) { ll k=0;top=0; for(int i=1;i<=n;++i) { k^=a[now][i]; if(!(k&(1LL<<j))) a[now+1][++top]=k,k=0; } if(!(k&(1LL<<j))&&top>=m) ++now,n=top; else ans|=(1LL<<j); } cout<<ans; return 0; }