标签 - 二进制

二进制 贪心    2016-09-27 13:58:15    211    0    0

Description

给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ... or c[m]。请求出总费用的最小值。
 

 

Input

第一行包含两个正整数n,m(1<=m<=n<=500000),分别表示序列的长度和需要划分的段数。
第一行包含n个整数,其中第i个数为a[i](0<=a[i]<=10^18)。
 

 

Output

输出一个整数,即总费用的最小值。
 

 

Sample Input

3 2
1 5 7

Sample Output

3

HINT

第一段为[1],第二段为[5 7],总费用为(1) or (5 xor 7) = 1 or 2 = 3。

 

Solution

给定一个长度为n的序列,要求分成m段,使得每段异或和的或值最小 

看到异或和的最值问题,一般都可以想到贪心

求出前缀异或和后从大到小按位确定

如果某一位上有至少m个数是0且第n个数是0,那么这一位就可以是0,同时将所有是1的数字标记为不可选

 

#include <bits/stdc++.h>
#define ll long long
#define getchar getchar_unlocked
int n, m;
bool no[500005];
ll ans, s[500005];

inline ll read()
{
    static char c; ll x = 0;
    while (!isdigit(c = getchar())) ;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - 48;
    return x;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++ i) {
        s[i] = read() ^ s[i - 1];
    }
    for (int K = 62; K >= 0; -- K) {
        if ((1ll << K) & s[n]) {
            ans |= 1ll << K;
            continue;
        }