字典树andXOR*
A.HDU 4825
你需要寫一種數據結構:
- 往其中加入一個正整數;
- 找出一個正整數,使得該數與詢問數的異或結果最大。
\(n\le 10^5\) 。
解
將數按二進制從高位到低位插入字典樹。
查詢時從高位往低位貪心。
Code
#include<cstdio> using namespace std; const int maxn=100003,maxlog=33; int t[maxn*maxlog][2],cnt; void insert(long long x){int p=1;for(int i=32;i>=0;i--){int nxt=(x>>i)&1;if(!t[p][nxt])t[p][nxt]=++cnt;p=t[p][nxt];} } long long query(long long x){int p=1;long long ret=0;for(int i=32;i>=0;i--){int nxt=!((x>>i)&1);if(t[p][nxt])p=t[p][nxt],ret|=(long long)nxt<<i;else p=t[p][!nxt],ret|=(long long)(!nxt)<<i;}return ret; } int n,m; int main(){int T;scanf("%d",&T);for(int TT=1;TT<=T;TT++){scanf("%d%d",&n,&m);cnt=1;for(int i=0;i<=n*maxlog;i++)t[i][0]=t[i][1]=0;for(int i=1;i<=n;i++){long long x;scanf("%lld",&x);insert(x);}printf("Case #%d:\n",TT);while(m--){long long x;scanf("%lld",&x);printf("%lld\n",query(x));}}return 0; }B. HDU 5536
有一個序列 \(s\) ,求 \(\max_{i,j,k,i≠j≠k} (s_i+s_j) \oplus s_k\) 。
\(1≤T≤1000\)
\(3≤n≤1000\)
\(0≤si≤10^9\)
There are at most \(10\) testcases with \(n>100\)
\(\text{Time Limit=9s}\)
解
直接 \(O(n^2\log n)\) 暴力插字典樹。
C. BZOJ 4260
有一個序列 \(A\) ,求 \(\max ((A[l_1] \oplus A[l_1+1] \oplus \dots \oplus A[r_1])+(A[l_2] \oplus A[l_2+1] \oplus \dots \oplus A[r_2]))(1\le l_1\le r_1<l_2\le r_2\le n)\)
\(n\le 4*10^5\) 。
解
處理出:
\(pre[i]=a[1] \oplus a[2] \oplus \dots \oplus a[i]\)
\(suf[i]=a[i] \oplus a[i+1] \oplus \dots \oplus a[n]\)
\(B[i]=\max(\max_{j\le i}pre[i] \oplus pre[j-1],B[i-1])\)
\(C[i]=\max(\max_{j≥i}suf[i] \oplus suf[j+1],C[i+1])\)
答案 \(=\max_{i\in [1,n-1]}(B[i]+C[i+1])\)
D. POJ 3764
有一棵樹,有邊權,求異或和最大的路徑的異或和。
解
設 \(dp[i]\) 為從1到 \(i\) 的路徑的異或和,答案 \(=\max_{i,j}(dp[i] \oplus dp[j])\) 。
請自己證明。
E. HDU 4757
一棵樹, \(Q\) 次詢問節點 \(x\) 到節點 \(y\) 的路徑上點權與 \(x\) 的異或的最大值。
解
可持久化trie
F. HDU 5661
求 \(\max_{a\le x\le b,c\le y\le d}(x \oplus y)(a,b,c,d\le 10^{18})\) 。
解
從高位往低位貪心。
Code
#include<cstdio> using namespace std; const int maxlog=60; bool valid(long long ans,int i,long long bit,long long l,long long r){bit=ans|(bit<<i);return (bit|((1ll<<i)-1))>=l&&bit<=r; } int main(){int T;scanf("%d",&T);for(int TT=1;TT<=T;TT++){long long a,b,c,d,ans1=0,ans2=0;scanf("%lld%lld%lld%lld",&a,&b,&c,&d);for(int i=59;i>=0;i--){bool v10=valid(ans1,i,0,a,b),v11=valid(ans1,i,1,a,b),v20=valid(ans2,i,0,c,d),v21=valid(ans2,i,1,c,d);if(v10&&v21)ans2|=1ll<<i;else if(v11&&v20)ans1|=1ll<<i;else if(v11&&v21)ans1|=1ll<<i,ans2|=1ll<<i;}printf("%lld\n",ans1^ans2);}return 0; }G. BZOJ 4245
給定一個長度為 \(n\) 的序列 \(a[1],a[2],\dots ,a[n]\),請將它劃分為 \(m\) 段連續的區間,設第 \(i\) 段的費用 \(c[i]\) 為該段內所有數字的異或和,則總費用為 \(c[1] | c[2] | \dots | c[m]\) 。請求出總費用的最小值。
解
記錄一下前綴異或和,然后枚舉一個高位,如果存在一個高位使得至少 \(m\) 個異或和為 \(0\) 且總異或和 \((prev[n])\) 為 \(0\) ,那么即可劃分,此時這一位對答案的貢獻為 \(0\) ,否則該位對答案的貢獻為一個 \(2\) 的冪。
I. J. 字典樹在字符串上的應用,略
K. HDU 4099
\(T=50000\) 組詢問,每次給出一個長度不超過40的數,求最小的斐波那契數,使得給定的數是這個數的前綴。如果前100000個數中沒有符合條件的,輸出-1。
解
高精計算前100000個斐波那契數,只需存儲前50位(類似double),然后全部插到字典樹里。
轉載于:https://www.cnblogs.com/BlogOfchc1234567890/p/10885610.html
總結
以上是生活随笔為你收集整理的字典树andXOR*的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP加密解密库
- 下一篇: codeforces 712 Memor