我是靠谱客的博主 称心枫叶,这篇文章主要介绍BZOJ 4260 Codechef REBXOR,现在分享给大家,希望可以做个参考。

1.题链接

 

求两个不相交的区间各自异或后相加的最大值。n的范围1<=n<=4e5

 

首先我们知道

前 i 个数的异或和前 j 个数的异或相异或: pre[i]^pre[j] = a[i+1]^a[i+2]^……^a[j],(i<j)。异或的后缀和类似。

 

于是我们可以先求出异或的前缀 suf[i]和后缀和 fi[i]。dp[i]表示前 i个数中任意区间异或的最大值,可以依次求与 suf[i] 相异或结果的最大值,然后把 suf[i] 插入到 01字典树中。

 

这样对于每个suf[i] 他会和之前的 i-1 个异或前缀和的共有部分所抵消,也就相当于是求任意区间的异或结果的最大值了。这样求出了一个区间,同理可利用后缀和求出另一个区间。

 

怎么保证两个区间不相交呢?可以通过使前后两个区间一个为不包含第 i个数的前部分区间,一个是包含第 i 个数的后部分区间就可以了。

 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) const int maxn=4e5+10; int n,m,num[maxn*32],ch[maxn*32][2],tot; int val[maxn*32],a[maxn],suf[maxn],fi[maxn],dp[maxn]; void init(){ tot=1; ch[0][0]=ch[0][1]=0; } void insert(int x){ int u=0; for(int i=32;i>=0;i--){ int v=(x>>i)&1; if(!ch[u][v]){ ch[tot][0]=ch[tot][1]=0; val[tot]=num[tot]=0; ch[u][v]=tot++; } u=ch[u][v]; num[u]++; } val[u]=x; } int query(int x){ int u=0; for(int i=32;i>=0;i--){ int v=(x>>i)&1; if(ch[u][v^1]&&num[ch[u][v^1]]) u=ch[u][v^1]; else u=ch[u][v]; } return x^val[u]; } int main(){ int i,j; scanf("%d",&n); dp[0]=suf[0]=fi[n+1]=0; for(i=1;i<=n;i++){ scanf("%d",&a[i]); suf[i]=suf[i-1]^a[i]; } init(); for(i=n;i>=1;i--) fi[i]=fi[i-1]^a[i]; int ans=0; insert(suf[0]); for(i=1;i<=n;i++){ dp[i]=max(dp[i-1],query(suf[i])); insert(suf[i]); } init(); insert(fi[n+1]); for(i=n;i>=1;i--){ ans=max(ans,dp[i-1]+query(fi[i])); insert(fi[i]); } printf("%dn",ans); return 0; }

 

最后

以上就是称心枫叶最近收集整理的关于BZOJ 4260 Codechef REBXOR的全部内容,更多相关BZOJ内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部