• sss


    <更新提示>

    <第一次更新>


    <正文>

    异或粽子

    Description

    小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
    小粽面前有 n 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 1 到 n。第 i 种馅儿具有一个非负整数的属性值 ai。每种馅儿的数量都足够多,即小粽不 会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 k 个粽子。
    小粽的做法是:选两个整数数 l, r,满足 1 ≤ l ≤ r ≤ n,将编号在[l, r] 范围内的所有 馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就 是我们常说的 xor 运算,即 C/C++ 中的 ˆ 运算符)
    小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的粽 子。小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!

    Input Format

    第一行两个正整数 n, k,表示馅儿的数量,以及小粽打算做出的粽子的数量。
    接下来一行为 n 个非负整数,第 i 个数为 ai,表示第 i 个粽子的属性值。
    对于所有的输入数据都满足:1 ≤ n ≤ 5 × 105, 1 ≤ k ≤ min{n(n−1)/2 , 2 × 105 } , 0 ≤ ai ≤4, 294, 967, 295。

    Output Format

    输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。

    Sample Input

    3 2 
    1 2 3
    

    Sample Output

    6
    

    解析

    题目大意:给定一个长度为(n)的序列,求序列异或和最大的(k)个子序列的异或值之和。

    枚举(n^2)个子区间显然不现实,注意到(k)(n)同阶,于是想到直接去找那(k)个区间。不妨对区间分分类:我们以右端点为分类的依据,将所有子区间分为(n)类。显然,我们可以先处理处每一类区间中异或和最大的一个,然后取每一类中最大的,这样在全局上一定也是最优的。

    记三元组(([x,y],l,r))代表右端点(r),左端点取值范围为([x,y])的这一类区间,其中,左端点取(l)时异或和最大。这时,我们只需把所有三元组塞进一个大根堆里,取异或值最大的就是当前的一个全局最优解。

    当我们取了一个目前值最大的区间后,显然这一类中区间还有其他方案可以选择,我们不能取完后直接将整个三元组剔除。根据定义,我们可以简单的将这个三元组分解为另两个格式相同的三元组(([x,l-1],l_1,r))(([l+1,r],l_2,r)),这样刚好包含了这类区间中左端点取其他值的情况,又可以加回堆中。

    那么问题就只剩下了给定一个右端点和左端点的取值范围,如何快速求最佳的左端点位置,使得区间异或和最大,发现这是可持久化(0/1trie)的基本功能。

    (Code:)

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 5e5+20;
    struct node { int x,y,l,r; long long val; };
    int n,k,cnt,root[N],Trie[N*33+N][2],latest[N*33+N];
    long long ans,a[N],s[N];
    inline int read(void)
    {
        int x = 0 , w = 0; char ch = ' ';
        while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
        while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
        return w ? -x : x;
    }
    inline long long readll(void)
    {
        long long x = 0 , w = 0; char ch = ' ';
        while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
        while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
        return w ? -x : x;
    }
    void insert(int id,int k,int p,int q)
    {
        if ( k < 0 ) { latest[q] = id; return; }
        int c = s[id] >> k & 1;
        if ( p != 0 ) Trie[q][c^1] = Trie[p][c^1];
        Trie[q][c] = ++cnt;
        insert( id , k-1 , Trie[p][c] , Trie[q][c] );
        latest[q] = max( latest[ Trie[q][0] ] , latest[ Trie[q][1] ] );
    }
    int query(int now,long long val,int k,int lim)
    {
        if ( k < 0 ) return latest[now];
        int c = val >> k & 1;
        if ( latest[Trie[now][c^1]] >= lim )
            return query( Trie[now][c^1] , val , k-1 , lim );
        else return query( Trie[now][c] , val , k-1 , lim );
    }
    inline void init(void)
    {
        latest[0] = -1 , root[0] = ++cnt;
        insert( 0 , 32 , 0 , root[0] );
        for ( register int i = 1 ; i <= n ; i++ )
        {
            s[i] = s[i-1] ^ a[i] , root[i] = ++cnt;
            insert( i , 32 , root[i-1] , root[i] );
        }
    }
    inline void input(void)
    {
        n = read() , k = read();
        for ( int i = 1 ; i <= n ; i++ )
            a[i] = readll();
    }
    inline bool operator < (node p1,node p2) { return p1.val < p2.val; }
    inline void solve(void)
    {
        priority_queue < node > Heap;
        for ( register int i = 1 ; i <= n ; i++ )
        {
            int pos = query( root[i-1] , s[i] , 32 , 0 );
            Heap.push( (node){ 0 , i-1 , pos , i , s[pos] ^ s[i] } );
        }
        while ( k-- )
        {
            node t = Heap.top(); Heap.pop();
            ans += t.val;
            int l , r , pos;
            l = t.x , r = t.l - 1;
            if ( l <= r )
            {
                pos = query( root[r] , s[t.r] , 32 , l );
                Heap.push( (node){ l , r , pos , t.r , s[pos] ^ s[t.r] } );
            }
            l = t.l + 1 , r = t.y;
            if ( l <= r )
            {
                pos = query( root[r] , s[t.r] , 32 , l );
                Heap.push( (node){ l , r , pos , t.r , s[pos] ^ s[t.r] } );
            }
        }
    }
    int main(void)
    {
        freopen("xor.in","r",stdin);
        freopen("xor.out","w",stdout);
        input();
        init();
        solve();
        printf("%lld
    ",ans);
        return 0;
    }
    

    <后记>

  • 相关阅读:
    lingpipe
    小白都会的邮件推送?你还不会吗?
    怎么拿到签到王者的勋章?
    分享几个学习鸿蒙的社区平台
    小白都会的一键软件搬家?你还不会吗?
    博客网站接入网站统计
    CSDN博客怎么别人的文章?
    HarmonyOS的组件、布局和事件三者的关系
    Markdown格式快速转换为富文本格式
    Python学习
  • 原文地址:https://www.cnblogs.com/Parsnip/p/11197156.html
Copyright © 2020-2023  润新知