hdu5715

来源:互联网 发布:matlab 2016a mac 编辑:程序博客网 时间:2024/06/06 18:01

二分+trie优化

dp?...不存在的。。。就是用了下dp的思想

trie里存的是前缀和,(我会告诉你我先开始是一段一段存的然后很高兴的写了。。无比复杂。。以为自己写了个很棒的新式trie。。结果别人就只用一个前缀就把我的所有功能完成 了,最搞笑的是我tm还给我写的trie加了个lazy优化。。。。。然后调试半天没弄出来。。。弃疗。。网上搜题解。。发现只需要一个前缀和就好了敲打

道理就是我们分10个trie树,然后每个trie树里的数代表这个数以前可以分成几个,然后就是插入加查询。。和普通trie不同的是.,trie上的每个节点都有个pos,用来满足每个区间不超过l这个条件。


#include<iostream>#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;struct nodee{int son[2];int pos;};nodee trie[11][305020];ll a[10010];int tot[11];bool isempty[11];int t, n, m, l;void insertt(int kind, ll v, int pos){int temp = 1;for (int i = 30; i >= 0; i--){int add = (v >> i) & 1;if (trie[kind][temp].son[add] == 0)trie[kind][temp].son[add] = tot[kind]++,trie[kind][tot[kind]-1].pos=pos;temp = trie[kind][temp].son[add];trie[kind][temp].pos = max(pos, trie[kind][temp].pos);}}ll getmaxx(ll v, int kind, int pos){int temp = 1;int ans = 0;for (int i = 30; i >= 0; i--){int add = (v >> i) & 1;if (trie[kind][temp].son[add ^ 1] && (pos - trie[kind][trie[kind][temp].son[add ^ 1]].pos <= l))temp = trie[kind][temp].son[add ^ 1],ans |= (1 << i);else{if (trie[kind][temp].son[add] && (pos - trie[kind][trie[kind][temp].son[add]].pos <= l))temp = trie[kind][temp].son[add];elsereturn -1;}}return ans;}void clearr(){for (int i = 1; i <= m; i++)for (int j = 1; j <= tot[i]; j++){trie[i][j].pos = 0;trie[i][j].son[0] = 0;trie[i][j].son[1] = 0;}for (int i = 1; i <= m; i++)tot[i] = 2, isempty[i] = 0;}bool solve(ll mid){for (int i = 1; i <= n; i++){ll insertv[20], pos[20];for (int k = 1; k <= m; k++)insertv[k] = -1, pos[k] = 0;for (int j = 1; j <= m; j++){if (j != 1){if (isempty[j - 1]){ll v = getmaxx(a[i], j - 1, i);if (v >= mid){if (i == n&&j == m)return true;insertv[j] = a[i];pos[j] = i;}}}else{if (i <= l&&a[i] >= mid){insertv[j] = a[i];pos[j] = i;if (i == n&&j == m)return true;}}}for (int k = 1; k <= m; k++){if (insertv[k]!=-1)insertt(k, insertv[k], pos[k]), isempty[k] = 1;}}return false;}int main(){scanf("%d", &t);int k = 1;while (t--){scanf("%d%d%d", &n, &m, &l);ll left = 0;ll right = 2000000000;for (int i = 1; i <= n; i++)scanf("%d", &a[i]),a[i] ^= a[i - 1];while (left<right){clearr();ll mid = (left + right) / 2 + 1;if (solve(mid))left = mid;elseright = mid - 1;}printf("Case #%d:\n%lld\n",k++, left);}}