bzoj4245 [ONTAK2015]OR-XOR (贪心)

4245: [ONTAK2015]OR-XOR

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 856 Solved: 469
[Submit][Status][Discuss]

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

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


从最高位贪心,判断每一位时加上高位的限制(某些位是否全为\(0\))即可;
因为段内是异或运算,所以两个满足限制的段合并后仍满足限制;
然后就变成了判断每一位能否分成不少于\(m\)个满足限制且这一位异或和为\(0\)的段;
AC GET☆DAZE

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 500039
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m,cnt;
ll num[N],now,ans;
int main()
{
    scanf("%d%d",&n,&m);
    for(int a=1;a<=n;a++)
    {
        scanf("%lld",&num[a]);
    }
    for(int a=60;~a;a--)
    {
        cnt=now=0;
        for(int b=1;b<=n;b++)
        {
            now^=num[b];
            if((now>>(a+1)<<(a+1)|ans)==ans && !(now>>a&1))
            {
                cnt++,now=0;
            }
        }
        if(cnt<m || now) ans|=(1ll<<a);
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Sinogi/p/9114752.html