奶牛异或(xor前缀和,01字典树)

奶牛异或

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

题目:

给你个数。让你找出一个连续子序列其和最大。若方案不唯一,输出右端点最左的方案,若还不唯一,输出最短的方案。


做法:

个数求的前缀和数组。问题转化成,在中选个数,其值最大。

做法见另一篇题解:https://blog.nowcoder.net/n/e27fd9137aed443f87b4c467a5d203d9

说明一下方案的输出思路:从左到右,统计选第个数和前个数中的某一个数值的最大值。若其值大于之前记录的方案,则该位置作为右端点更优。同时我们在上记录时保证选出来的左端点最靠右即可保证值最大的同时序列长度最短。具体就是在上插入同一个数时只记录后一个位置的


代码:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 7;
int pre[N];
struct Trie{
    static const int N = 5e6 + 7;
    int tot, ch[N][2], tag[N];
    void insert(int x, int id){
        int now = 0;
        for (int i = 20; i >= 0; --i){
            int b = (x>>i)&1;
            if (!ch[now][b]) ch[now][b] = ++tot;
            now = ch[now][b];
        }
        tag[now] = id;
    }
    pii ask(int x){
        int now = 0, ans = 0;
        for (int i = 20; i >= 0; --i){
            int b = (x>>i)&1;
            if (ch[now][b^1]) now = ch[now][b^1], ans |= (1<<i);
            else now = ch[now][b];
        }
        return make_pair(ans, tag[now]);
    }
}trie;
int main(void){
    IOS;
    int n; cin >> n;
    for (int i = 1; i <= n; ++i){
        int x; cin >> x; pre[i] = pre[i-1]^x;
    }
    trie.insert(0, 1);
    int ans = -1, l, r;
    for (int i = 1; i <= n; ++i){
        pii tmp = trie.ask(pre[i]);
        if (ans < tmp.first) ans = tmp.first, l = tmp.second, r = i;
        trie.insert(pre[i], i+1);
    }
    cout << ans << ' ' << l << ' ' << r << endl; 
    return 0;
}
全部评论

相关推荐

jack_miller:我给我们导员说我不在这里转正,可能没三方签了。导员说没事学校催的时候帮我想办法应付一下
点赞 评论 收藏
分享
HNU_fsq:建议直接出国,这简历太6了。自愧不如
点赞 评论 收藏
分享
4 1 评论
分享
牛客网
牛客企业服务