连续子串最大最小异或值 Trie+Xor LightOJ 1269 Consecutive Sum

4 篇文章 0 订阅
3 篇文章 0 订阅

http://lightoj.com/volume_showproblem.php?problem=1269

题意:

给定一个序列,求选定一段区间的亦或和最大值和最小值。


解析:
由于是区间问题,很容易就能想到是要先求前缀异或和。 
可以对所有前缀和建立字典树,节点的末尾保存二进制转化成十进制的值。 
先查询,再插入。 
可以先将所有的的数字转化成二进制字符串,高位在前,低位在后。 
最大值很简单,查找时然后尽量往反向走; 
最小则需要尽量往正向走。 

知道走到尽头时把找到的十进制,异或上当前的值。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 50005;
const int maxnode = MAXN * 33;
const int sigma_size = 2;
const int INF = (1LL << 31) - 1;

struct Trie {
    int ch[maxnode][sigma_size];
    int val[maxnode];
    int sz;

    void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
    Trie() { clear(); }

    int idx(char c) { return c - '0'; }

    void insert(char *s, int v) {
        int u = 0, n = strlen(s);
        for(int i = 0; i < n; i++) {
            int c = idx(s[i]);
            if(!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[u] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = v;
    }

    //^0 equal
    //^1 opposite
    int find(char *s, int value, int dir) {
        int u = 0, n = strlen(s);   
        for(int i = 0; i < n; i++) {
            int c = idx(s[i]);
            int v = c ^ dir;
            if(!ch[u][v])
                v ^= 1;
            u = ch[u][v];
        }
        return val[u] ^ value;
    }

} trie;

int n, sum[MAXN], A[MAXN];
char bit[33];

void trans(char *s, int v) {
    for(int i = 31; i >= 0; i--)
        s[i] = ((v >> i) & 1) + '0';
    s[32] = '\0';
    reverse(s, s+32);
}

int main() {
    int T, cas = 1;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        trie.clear();

        sum[0] = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &A[i]);
            sum[i] = sum[i-1] ^ A[i];
        }

        trans(bit, 0);
        trie.insert(bit, 0);

        int maxv = -INF, minv = INF;
        int mx, mi;
        for(int i = 1; i <= n; i++) {
            trans(bit, sum[i]);
            mi = trie.find(bit, sum[i], 0);
            mx = trie.find(bit, sum[i], 1);
            minv = min(mi, minv);
            maxv = max(mx, maxv);
            trie.insert(bit, sum[i]);
        }

        printf("Case %d: %d %d\n", cas++ , maxv, minv);
    }
    return 0;
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值