01字典树解决异或问题学习、

来源:互联网 发布:中国化妆品数据网 编辑:程序博客网 时间:2024/06/18 17:53

联系衔接:blcakcat

HDU 4825

从最高为开始贪心,如何可以走当前位的异或结果就走异或结果否则就走当前结果

#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <ctime>#include <iostream>#include <algorithm>#include <sstream>#include <string>#include <vector>#include <queue>#include <stack>#include <map>#include <set>#include <utility>using namespace std;#define LL long long#define pb push_back#define mk make_pair#define mst(a, b)memset(a, b, sizeof a)#define REP(i, x, n)for(int i = x; i <= n; ++i)const int MOD = 1e9 + 7;const int qq = 1e5 + 10;const int INF = 1e9 + 10;LL value[32 * qq];int ch[32 * qq][2];int n, m, node_cnt;void Init() {node_cnt = 1;mst(ch[0], 0);}void Insert(LL x) {int cur = 0;for(int i = 32; i >= 0; --i) {int idx = (x >> i) & 1;if(!ch[cur][idx]) {mst(ch[node_cnt], 0);ch[cur][idx] = node_cnt;value[node_cnt++] = 0;}cur = ch[cur][idx];}value[cur] = x;}LL Query(LL x) {int cur = 0;for(int i = 32; i >= 0; --i) {int idx = (x >> i) & 1;if(ch[cur][idx ^ 1])cur = ch[cur][idx ^ 1];elsecur = ch[cur][idx];}return value[cur];}int main(){int t;scanf("%d", &t);int Cas = 0;while(t--) {Init();scanf("%d%d", &n, &m);for(int i = 0; i < n; ++i) {LL x;scanf("%lld", &x);Insert(x);}printf("Case #%d:\n", ++Cas);for(int i = 0; i < m; ++i) {LL x;scanf("%lld", &x);printf("%lld\n", Query(x));}}return 0;}


HDU 5536

题意:给出n个求,求出(si + sj) ^ sk 的最大值,i,j,k互不相等

思路:先对所有数建一颗01字典树,然后枚举i,j,将si与sj从字典序中删除,贪心找最大的结果

#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <ctime>#include <iostream>#include <algorithm>#include <sstream>#include <string>#include <vector>#include <queue>#include <stack>#include <map>#include <set>#include <utility>using namespace std;#define LL long long#define pb push_back#define mk make_pair#define mst(a, b)memset(a, b, sizeof a)#define REP(i, x, n)for(int i = x; i <= n; ++i)const int MOD = 1e9 + 7;const int qq = 1e3 + 10;const int INF = 1e9 + 10;int ch[32 * qq][2], value[32 * qq], node_cnt, n;LL num[qq];void Init() {node_cnt = 1;mst(ch[0], 0);mst(value, 0);}void Insert(LL x) {int cur = 0;for(int i = 32; i >= 0; --i) {int idx = (x >> i) & 1;if(!ch[cur][idx]) {mst(ch[node_cnt], 0);ch[cur][idx] = node_cnt++;}cur = ch[cur][idx];value[cur]++;}}void Delete(LL x) {int cur = 0;for(int i = 32; i >= 0; --i) {int idx = (x >> i) & 1;cur = ch[cur][idx];value[cur]--;}}LL Query(LL x) {int cur = 0;LL ans = 0;for(int i = 32; i >= 0; --i) {int idx = (x >> i) & 1;if(ch[cur][idx ^ 1] && value[ch[cur][idx ^ 1]]) {ans |= (1LL << i);cur = ch[cur][idx ^ 1];} else {cur = ch[cur][idx];}}return ans;}int main(){int t;scanf("%d", &t);while(t--) {Init();scanf("%d", &n);for(int i = 1; i <= n; ++i) {scanf("%lld", num + i);Insert(num[i]);}LL maxn = 0;for(int i = 1; i <= n; ++i) {Delete(num[i]);for(int j = i + 1; j <= n; ++j) {LL x = num[i] + num[j];Delete(num[j]);maxn = max(maxn, Query(x));Insert(num[j]);}Insert(num[i]);}printf("%lld\n", maxn);}return 0;}


HDU 3460

题意:有n个字符串,你有一个打印机,你要使用打印机输出所有字符串,打印机有三种操作,增加一个字符,删除一个字符,打印,问最少需要操作多少次

思路:很明显可以建一颗字典树,但关键在于怎么求解,可以这样思考首先我们知道打印每个字符串的贡献是n,那么现在我们还需要计算打印的贡献和删除的贡献,我们建了一颗字典树,那么字典树上的所有节点都是需要打印的,这就是所有打印的贡献,删除的贡献呢?我们要明确最后肯定只剩下一个字符串,所以之前的肯定会被删除掉,所以我们假设全部删除,再加上一个最长字符串即删除操作的贡献

#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <ctime>#include <iostream>#include <algorithm>#include <sstream>#include <string>#include <vector>#include <queue>#include <stack>#include <map>#include <set>#include <utility>using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(a, b)memset(a, b, sizeof a)#define REP(i, x, n)for(int i = x; i <= n; ++i)const int MOD = 1e9 + 7;const int qq = 1e4 + 10;const int INF = 1e9 + 10;int ch[qq * 26][26];int node_cnt, n;char st[qq];void Init() {mst(ch[0], 0);node_cnt = 1;}void Insert() {int cur = 0;int len = strlen(st);for(int i = 0; i < len; ++i) {int idx = st[i] - 'a';if(!ch[cur][idx]) {mst(ch[node_cnt], 0);ch[cur][idx] = node_cnt++;;}cur = ch[cur][idx];}}int main(){while(scanf("%d", &n) != EOF) {Init();int maxn = 0;for(int i = 0; i < n; ++i) {scanf("%s", st);maxn = max(maxn, (int)strlen(st));Insert();}printf("%lld\n", -maxn + (node_cnt - 1) * 2LL + n);}return 0;}