华中农业大学第五届程序设计大赛 H MathematicalGame [01字典树]【字典树】

题目链接:http://acm.hzau.edu.cn/problem.php?id=1206
——————————————————————————————————————
1206: MathematicalGame
Time Limit: 2 Sec Memory Limit: 1280 MB
Submit: 170 Solved: 26
[Submit][Status][Web Board]
Description
Xiao Ming likes to play mathematical games very much. One day, he gets a sequence of n positive integers. XOR (l , r) is defined as the XOR and of all numbers in a continuous interval. Now, Xiao Ming wants to know the intervals which make the XOR (l , r) become largest.

Require l, r.

Input
There is an integer T at the first line, indicate the case of data.

In each case, there is an integer N at the first line, indicate the length of the sequence. And there are N integers, a1, a2, … , an, at the second line. (N <= 1,000,000)

Output
In each case, the first line is “Case #k:”, k is the number of test cases, the next line includes two integers l and r, which separated by a space.

l, r output in lexicographic order if there are multiple results.

Sample Input
1
5
1 2 3 4 5
Sample Output
Case #1:
3 4

————————————————————————————————————————
题目大意:
问你区间异或值最大的区间是多少,如果值有多个,输出字典序最小的那个

解题思路:

相信大家都会 区间内选两个值,异或最大

那么这个也一样,只要维护的是前缀异或和就好了,这样就变成了经典问题。

然后维护结果就好了

附本题代码
——————————————————————————————————

#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N   = 2e6+7;
//const int INF = (~(1<<31));

int read(){
    int x=0,f=1;char ch = getchar();
    while(ch<'0'||ch>'9') ch = getchar();
    while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch = getchar();}
    return x;
}
/*******************************************/

int n,a,x;
int trie[N*31][2],val[N*31],cnt;

int l,r,mx;

void inserttrie(int x,int id){
    int now=0,bt;
    for(int i=30;i>=0;i--){
        bt = (x&(1<<i))?1:0;
        if(!trie[now][bt]) trie[now][bt] = ++cnt;
        now=trie[now][bt];
    }
    if(-1==val[now]) val[now]=id;
}

int ask(int x,int y){
//    printf("%d ->" ,x);
    int now=0,bt,v=0;
    for(int i=30;i>=0;i--){
        bt = (x&(1<<i))?1:0;
//printf("%d",bt);
        if(trie[now][1-bt]) bt=1-bt,v|=(1<<i);


        now=trie[now][bt];
    }
//    puts("    <-");
    int vn = val[now]+1;
//    printf("%d %d\n",v,mx);
    if(v>mx) mx=v,l=vn,r=y;
    if(v==mx){if(vn<l||vn==l&&y<r)l=vn,r=y;}
}

int main(){
    memset(trie,0,sizeof(trie));
    memset(val,-1,sizeof(val));

    int _,kcase = 0;
    scanf("%d",&_);
    while(_--){
        scanf("%d",&n);l=r=1;
        a=0;cnt=0;mx=0;
        inserttrie(a,0);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            a^=x;
//            printf("%d%c",a,(i==n)?'\n':' ');
            ask(a,i);
            inserttrie(a,i);
        }
        printf("Case #%d:\n",++kcase);
        printf("%d %d\n",l,r);

        for(int i=0;i<=cnt;i++){
            trie[i][0]=trie[i][1]=0;
            val[i]=-1;
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值