奶牛异或

奶牛异或

https://ac.nowcoder.com/acm/problem/22998

奶油异或

题意

让你找一个连续区间异或和最大,如果有多种方案,输出右端点最小的,如果还有多种方案,输出最短的

分析

关于异或,有这样一个性质 ,如果用 表示 的异或前缀和,那么有 ,就是说这样可以很轻松的求的一个区间的异或和
所以在 字典树上,我们可以插入 的异或前缀和,结尾的时候标记一下这是谁的前缀和,那么查询就是和这个专题的上一道题一样
需要注意的是,如何得到“右端点最小,最短的方案呢”
显然第一个严格大于上一次的答案保证了右段点最小,因为字典树的性质,相同的数在叶子节点上的信息又是最靠右的,那么这个有保证了最短,所以不需要可以做什么其他的操作来得到答案

Code

#include <cstdio>

const int maxn = 1e5 + 10;
int n, id, ans(-1), l, r, temp;
int son[maxn * 32][2], end[maxn * 32];

inline int __read()
{
    int x(0), t(1);
    char o (getchar());
    while (o < '0' || o > '9') {
        if (o == '-') t = -1;
        o = getchar();
    }
    for (; o >= '0' && o <= '9'; o = getchar()) {
        x = (x << 1) + (x << 3) + (o ^ 48);
    }
    return x * t;
}

inline void Insert(int temp, int x)
{
    int p(0);
    for (int i = 20; ~i; --i) {
        int sta = (temp >> i) & 1;
        if (!son[p][sta]) son[p][sta] = ++id;
        p = son[p][sta];
    }
    end[p] = x;
}

inline void find(int x)
{
    int p(0), res(0);
    for (int i = 20; ~i; --i) {
        int sta = (temp >> i) & 1;
        if (son[p][sta ^ 1]) p = son[p][sta ^ 1], res |= 1 << i;
        else if (son[p][sta]) p = son[p][sta];
        else break;
    }
    if (res > ans) ans = res, l = end[p], r = x;
}

int main()
{
    n = __read();
    Insert(0, 0);
    for (int i = 1; i <= n; ++i) {
        temp ^= __read();
        find(i);
        Insert(temp, i);
    }
    printf ("%d %d %d\n", ans, l + 1, r);
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
06-18 16:15
点赞 评论 收藏
分享
06-15 18:44
黄淮学院 Java
Lynn012:如果是居民楼还是算了吧,看着有点野呢
点赞 评论 收藏
分享
06-15 02:05
已编辑
南昌航空大学 数据分析师
Eason三木:你如果想干技术岗,那几个发公众号合唱比赛的经历就去掉,优秀团员去掉,求职没用。然后CET4这种不是奖项,是技能,放到下面的专业技能里或者单独列一个英语能力。 另外好好改改你的排版,首行缩进完全没有必要,行间距好好调调,别让字和标题背景黏在一起,你下面说能做高质量PPT你得展现出来啊,你这简历排版我用PPT做的都能比你做的好。 然后自我评价,你如果要干数据工程师,抗压能力强最起码得有吧。
点赞 评论 收藏
分享
评论
3
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务