A.HDU 4825
你需要写一种数据结构:
- 往其中加入一个正整数;
- 找出一个正整数,使得该数与询问数的异或结果最大。
(nle 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:
",TT);
while(m--){
long long x;
scanf("%lld",&x);
printf("%lld
",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)
( ext{Time Limit=9s})
解
直接 (O(n^2log 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]))(1le l_1le r_1<l_2le r_2le n))
(nle 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_{jle 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_{iin [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_{ale xle b,cle yle d}(x oplus y)(a,b,c,dle 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
",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),然后全部插到字典树里。