百度之星复赛 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},L为3,可以划分为{1|2,3,4} 或 {1,2|3,4} 或 {1,2,3|4},最小的异或值分别为1,3,0,所以选第二种分割方法。
今天,它发明了一种XOR新游戏,最开始,它有一个长度为N的数组,度度熊可以任意添加分割线,将数组划分为M段,且每段长度小于等于L。
当然这是个和XOR有关的游戏,度度熊希望所有分组内异或和的最小值最大。
比如,长度为4的数组{1,2,3,4},L为3,可以划分为{1|2,3,4} 或 {1,2|3,4} 或 {1,2,3|4},最小的异或值分别为1,3,0,所以选第二种分割方法。
Input
第一行为T,表示输入数据组数。
对于每组数据,第一行包含三个整数N,M,L,第二行包含N个数,表示数组。
1≤T≤300
1≤N≤10000,1≤M≤10,1≤L≤N
1≤Ai≤109
对于每组数据,第一行包含三个整数N,M,L,第二行包含N个数,表示数组。
1≤T≤300
1≤N≤10000,1≤M≤10,1≤L≤N
1≤Ai≤109
Output
对第i组数据,输出
Case #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; }