搜索题

搜索题

题目描述

 

小H是一个热爱出毒瘤题的女孩子。

小H按照老师要求出了一道搜索题。这是一道只有题目和搜索有关的题目。

现在你有一个长度为n的数列A,每个数为ai,你要将它分成m段,每段至少1个数。令每段的异或值为ci。

你需要最小化所有ci或起来的值。

 

【数据范围】 1≤m≤n≤5*10^5,0≤ai≤10^18

solution

考虑从高位开始贪心

如果这一位出现了奇数个一,那么这一位就应该是不合法的,可以跳过

如果是偶数个,那么我们可以贪心判断。

那么怎么在保证之前合法的时候寻找当下合法的的方案呢

我开了个变量M 表示第i位是否能做到合法,如果能就为1

如果当前所有为的异或和为t,且t&m==0 则当前位为一个合法的划分

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define maxn 500005
using namespace std;
int n,m,tot;
ll a[maxn],flag,Max,ans,M;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        Max=max(Max,a[i]);
    }
    int bs;
    for(bs=0;(ll)(1LL<<bs)<=Max;bs++);M=0;
    for(int ws=bs;ws>=0;ws--){
        int num=0;
        for(int i=1;i<=n;i++)
        if(a[i]&((ll)(1LL<<ws)))num++;
        if(num%2==0){
            M+=(ll)(1LL<<ws);
            int cnt=0;ll t=0;
            for(int i=1;i<=n;i++){
                t=t^a[i];
                if((t&M)==0)cnt++,t=0;
                if(cnt==m)break;
            }
            if(cnt!=m)ans+=(ll)(1LL<<ws),M-=(ll)(1LL<<ws),tot--;
        }
        else ans+=(ll)(1LL<<ws);
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/liankewei/p/10358789.html