Codeforces 282E. Sausage Maximization【trie树(非指针版)】

题目大意:

给出一串数,pre[i](前i个数的异或)为a[0]~a[i-1]的异或,post[i](后缀的异或)为a[i]~a[n-1]的异或,求pre[i]^post[j]的最大值(0<=i<=j<=n),其中,pre[0]=0,post[n]=0(表示一个数都不选)。

做法:

利用trie树将后缀或者前缀存储起来,首先从pre[n]开始,往前遍历,对于每个前缀,将此时的后缀添加到trie树中,再在trie中寻找与当前前缀异或之后能得到最大的值。

在trie中存储数的时候,将该数的二进制的数位的每一位存进去,由于异或之后不可能增加位数,那么我们要找最大的值的话,只需要从第一位开始,保证这一位能为1的时候取一,如果不能取一则取0,那么最后的结果一定是最大的。

这里用的trie树是非指针版的。。自己写的,觉得指针太复杂(自己太弱....),用存储节点下标的方式。

注意存储数的时候,需要将40位全部存进去(2^40是大于10^12的第一个二次幂数),不然处理位数会很麻烦。这样的话,trie树中节点数最多也就40*10^5个,也是可行的。

由于数的范围是10^12,会爆int,得用long long ,还得特别小心特别小心!像(1<<40)这样的操作是会爆int的,必须写成这样(1LL<<40)才行。博主在这里被坑了好久。。要不是大牛提醒的话,我都不知道什么时候才能发现这个问题。。。推掉重写也是有可能的!。。。

详细见代码和注释:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100010
using namespace std;
struct node
{
    long long nxt[2];//存储nxt节点在数组中的下标
}trie[N*40];
long long all_idx,bit[42],num[N],n;
long long createNode()
{
    memset(trie[all_idx].nxt,-1,sizeof(trie[all_idx].nxt));//没有访问过的置为-1
    return all_idx++;
}
void insert_Node(long long root,long long cur)
{
    memset(bit,0,sizeof(bit));//存储cur的二进制数
    long long len=0;
    while(cur)
    {
        bit[len++]=cur&1;
        cur>>=1;
    }
    long long idx=root;
    //将40位全部存进去
    for(len=40;len>=0;len--)
    {
        long long k=bit[len];
        if(trie[idx].nxt[k]==-1)
            trie[idx].nxt[k]=createNode();
        idx=trie[idx].nxt[k];
    }
}
long long running(long long root,long long cur)
{
    long long sum=0;
    memset(bit,0,sizeof(bit));
    long long len=0;
    while(cur)
    {
        bit[len++]=cur&1;
        cur>>=1;
    }
    long long idx=root;
    for(len=40;len>=0;len--)
    {
        long long k=!bit[len];/////两个数不相同,异或结果为1
        if(trie[idx].nxt[k]!=-1) {
            sum+=(1LL<<len);///////一定要加LL,被坑了好久。。。也是无语了
            idx=trie[idx].nxt[k];
        }
        else idx=trie[idx].nxt[!k];//如果不存在这样的数,只能取0,并且从这边走下去。
    }
    return sum;
}
int main()
{
    scanf("%I64d",&n);
    long long pre=0,post=0;
    long long ans=0;
    for(long long i=0;i<n;i++)
        scanf("%I64d",num+i),pre^=num[i];
    long long root=createNode();
    for(long long i=n-1;i>=0;pre^=num[i],post^=num[i],i--)
    {
        insert_Node(root,post);
        ans=max(ans,running(root,pre));
    }
    ans=max(ans,running(root,pre));//判断取0个前缀的时候的值
    cout<<ans<<endl;
    return 0;
}
时间: 2024-11-13 05:32:46

Codeforces 282E. Sausage Maximization【trie树(非指针版)】的相关文章

Codeforces 282E Sausage Maximization(字典树)

题目链接:282E Sausage Maximization 题目大意:给定一个序列A,要求从中选取一个前缀,一个后缀,可以为空,当时不能重叠,亦或和最大. 解题思路:预处理出前缀后缀亦或和,然后在字典树中维护,每次添加并查询,过程中维护ans. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef lon

codeforces 282E. Sausage Maximization Trie

题目链接 给n个数, 让你找出一个前缀和一个后缀, 它们异或完以后最大, 前缀和后缀都是异或得来的, 可以为空, 为空时按0算.前缀后缀不可覆盖. 这题好神, 竟然是Trie树... 首先将所有数的异或算出来作为初始的后缀, 初始前缀为0. 然后往字典树里插入前缀, 在对后缀进行查找, 查找时, 从高位往低位找, 如果后缀的第i位为0, 那么就找字典树里这一位有没有1, 有1就往1的那一条路找,没有就只能往0那一条路找. 具体看代码. #include <iostream> #include

CF282 E Sausage Maximization[trie树]

给n个数 求异或前缀(从前连续取一些数全作异或)和异或后缀(从后连续取一些数全作异或)异或的最大值 好坑啊,指针好坑啊 第一道trie树 简单说下解法(其实壳还是不深): 先异或所有数作为初始后缀 然后从前往后的数逐个从后缀出来,进入前缀, 在这个过程中,都把当前前缀变成二进制压入trie,然后当前后缀变成二进制从高位到低位尽量取和它数位不同的值,沿着trie往下走,得到一个最好的数,然后和后缀异或,维护最大值 简直了,指针就是坑 其实还是自己有点坑 说下遇到的坑吧 一开始没有全存64位数(导致

字典树模板( 指针版 &amp;&amp; 数组版 )

模板 : #include<string.h> #include<stdio.h> #include<malloc.h> #include<iostream> #include<algorithm> using namespace std; const int maxn = 26; struct Trie { Trie *Next[maxn]; int v; inline void init(){ this->v = 1; for(int

【转】 史上最详尽的平衡树(splay)讲解与模板(非指针版spaly)

ORZ原创Clove学姐: 变量声明:f[i]表示i的父结点,ch[i][0]表示i的左儿子,ch[i][1]表示i的右儿子,key[i]表示i的关键字(即结点i代表的那个数字),cnt[i]表示i结点的关键字出现的次数(相当于权值),size[i]表示包括i的这个子树的大小:sz为整棵树的大小,root为整棵树的根. 再介绍几个基本操作: [clear操作]:将当前点的各项值都清0(用于删除之后) inline void clear(int x){ ch[x][0]=ch[x][1]=f[x]

树-trie树

字典树(trie树) (图f) 字典树是一种以树形结构保存大量字符串.以便于字符串的统计和查找,经常被搜索引擎系统用于文本词频统计.它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高.具有以下特点(图f):(1)根节点为空:(2)除根节点外,每个节点包含一个字符:(3)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串.(4)每个字符串在建立字典树的过程中都要加上一个区分的结束符,避免某个短字符串正好是某个长字符串的前缀而淹没. T

Hihocoder #1014 : Trie树 (字典数树统计前缀的出现次数 *【模板】 基于指针结构体实现 )

#1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能对于每一个我给出的字符串,都在这个词典里面找到以这个字符串开头的所有单词呢?” 身经百战的小Ho答道:“怎么会不能呢!你每给我一个字符串,我就依次遍历词典里的所有单词,检查你给我的字

trie树 Codeforces Round #367 D Vasiliy&#39;s Multiset

1 // trie树 Codeforces Round #367 D Vasiliy's Multiset 2 // 题意:给一个集合,初始有0,+表示添加元素,-去除元素,?询问集合里面与x异或最大的值 3 // 思路:思路很好想,建立trie树,再贪心当前位是1则选0,0则选1 4 5 6 #include <bits/stdc++.h> 7 using namespace std; 8 #define LL long long 9 const double inf = 123456789

CodeForces - 778C: Peterson Polyglot (启发式合并trie树)

Peterson loves to learn new languages, but his favorite hobby is making new ones. Language is a set of words, and word is a sequence of lowercase Latin letters. Peterson makes new language every morning. It is difficult task to store the whole langua