百度之星复赛 1004 / hdu5715 二分dp+trie

XOR 游戏

 

Problem Description
 
众所周知,度度熊喜欢XOR运算[(XOR百科)](http://baike.baidu.com/view/674171.htm)。

今天,它发明了一种XOR新游戏,最开始,它有一个长度为N的数组,度度熊可以任意添加分割线,将数组划分为M段,且每段长度小于等于L

当然这是个和XOR有关的游戏,度度熊希望所有分组内异或和的最小值最大。

比如,长度为4的数组{1,2,3,4}L3,可以划分为{1|2,3,4} 或 {1,2|3,4} 或 {1,2,3|4},最小的异或值分别为1,3,0,所以选第二种分割方法。
 

 

Input
 
第一行为T,表示输入数据组数。

对于每组数据,第一行包含三个整数N,M,L,第二行包含N个数,表示数组。

1T300

1N10000,1M10,1LN

1Ai109
 

 

Output
 
对第i组数据,输出

Case #i:

然后输出一行,仅包含一个整数,表示满足条件分组方法的最小异或值。
 

 

Sample Input
 
2 4 2 3 1 2 3 4 4 3 2 5 4 3 2
 

 

Sample Output
 
Case #1: 3 Case #2: 2
 

题解:

  二分答案check mid

  就是在划分m次的情况下 使得当前f[x][i] 表示前i个位置数划分成x快能否使得最小值得最大值大于mid

  维护长度L+1,将这些数的前缀放入trie中,尽量跑出当前能得到的最大值是否大于mid

  代码来自jiry

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int N = 1e4+20, M = 1e6+10, mod = 1e9+7, inf = 1e9+1000;
typedef long long ll;

int cas = 1,n,m,L,ans,tot,a[N];
int f[11][N];
struct ss{
    int ls,rs,sz;
}tr[N*64];
void ins(int x,int key,int v) {
    tr[x].sz += v;
    for(int i=30;~i;i--) {
        if(key&(1<<i)) {
            if(!tr[x].rs) {
                tr[++tot]  = (ss) {0,0,0};
                tr[x].rs = tot;
            }
            x = tr[x].rs;
        }
        else {
            if(!tr[x].ls) {
                tr[++tot] = (ss) {0,0,0};
                tr[x].ls = tot;
            }
            x = tr[x].ls;
        }
        tr[x].sz += v;
    }
}
int ask(int x,int key) {
    int ret = 0;
    for(int i=30;~i;i--) {
        if(key&(1<<i)) {
            if(tr[tr[x].ls].sz)ret += (1<<i),x = tr[x].ls;else x = tr[x].rs;
        }
        else {
            if(tr[tr[x].rs].sz) ret += (1<<i),x = tr[x].rs;else x = tr[x].ls;
        }
    }
    return ret;
}
int check(int x) {
    memset(f,0,sizeof(f));
    f[0][0] = 1;
    for(int j=1;j<=m;j++) {
        tr[tot = 1] = (ss) {0,0,0};
        for(int i=1;i<=n;i++) {
            if(f[j-1][i-1]) ins(1,a[i-1],1);
            if(i>L&&f[j-1][i-L-1]) ins(1,a[i-L-1],-1);
            f[j][i] = (ask(1,a[i])>=x);
        }
    }
    return f[m][n];
}
void solve() {
    scanf("%d%d%d",&n,&m,&L);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]), a[i] ^= a[i-1];
    int l = 0, r = 2e9+10;
    while(l<=r) {
        int mid = (l+r)>>1;
        if(check(mid)) l = mid + 1, ans = mid;
        else r = mid - 1;
    }
    printf("Case #%d:\n%d\n",cas++,ans);
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        solve();
    }
    return 0;
}

 

posted @ 2016-05-30 18:08  meekyan  阅读(326)  评论(0编辑  收藏  举报