Cow XOR
Adrian Vladu -- 2005
Farmer John is stuck with another problem while feeding his cows. All of his N (1 ≤ N ≤ 100,000) cows (numbered 1..N) are lined up in front of the barn, sorted by their rank in their social hierarchy. Cow #1 has the highest rank; cow #N has the least rank. Every cow had additionally been assigned a non-unique integer number in the range 0..(2 - 1).
Help FJ choose which cows will be fed first by selecting a sequence of consecutive cows in the line such that the bitwise "xor" between their assigned numbers has the maximum value. If there are several such sequences, choose the sequence for which its last cow has the highest rank. If there still is a tie, choose the shortest sequence.
TIME LIMIT: 0.5 sec
PROGRAM NAME: cowxor
INPUT FORMAT
- Line 1: A single integer N
- Lines 2..N+1: N integers ranging from 0 to 2 - 1, representing the cows' assigned numbers. Line j describes cow of social hierarchy j-1.
SAMPLE INPUT (file cowxor.in)
5
1
0
5
4
2
INPUT DETAILS:
There are 5 cows. Cow #1 had been assigned with 1; cow #2 with 0; cow #3 with 5; cow #4 with 4; cow #5 with 2.
OUTPUT FORMAT
- Line 1: Three space-separated integers, respectively: the maximum requested value, the position where the sequence begins, the position where the sequence ends.
SAMPLE OUTPUT (file cowxor.out)
6 4 5
OUTPUT DETAILS:
4 xor 2 = 6 (001) xor (010) = (011)
————————————————————————题解
首先是死活都没有想出来标解
然后是造福大众的Analysis
Cow XOR
Suppose that we know the k first bits of binary representation of the greatest possible xor. If there exists a sequence such that its xor (which we shall call q) on the first k bits agrees with those -- and the next bit is '1' -- then we know, that k+1'th bit of the greatest xor will be '1', because if not, then q would be greater.
如果我们知道了最棒的异或二进制前k位,存在一个序列使它的k位是这样的,然后下一位是1(如果我们可以办到),因为如果不是答案就不会最大。
The solution first computes values xr[], where xr[q] equals xor of all the cows' values from 1 to q - then, xor of the sequence a..b quals xr[b] xor xr[a-1].
It then runs a loop over all possible exponents e of 2 (starting from 21 downwards), updating arrays pop[] and best[]. It is assumed that after finishing the loop with exponent e (and before entering the loop, with e assumed to be 22), that for every 0 ≤ q ≤ N:
这个解答先定义变量xr[],这是一个异或前缀和【公子是一个力求简洁的翻译】。然后循环二进制拆位从22开始倒序枚举,然后对于每个0 ≤ q ≤ N
- xr[pop[q][0]]'s and xr[q]'s binary representations are the same on positions e, e+1, etc., and pop[q][0] is biggest possible with 0 ≤ pop[q][0] < q. If there's no such pop[q][0] possible, then pop[q][0] = -1.
- xr[pop[q][1]]'s and xr[q]'s binary representations are the same on positions e+1, e+2, etc., different on position e, and pop[q][1] is biggest possible with 0 ≤ pop[q][1] < q. If there's no such pop[q][1] possible, then pop[q][1] = -1.
- if X would be equal biggest possible xor, then xr[best[q]] xor xr[q]'s in equal X's binary representation on positions e, e+1, etc., and best[q] is biggest possible with 0 ≤ best[q] < q. If there's no such best[q] possible, then best[q] = -1.
After performing the loop with e = 0, for each 0 ≤ q ≤ N, best[q] = -1 or xr[best[q]] xor xr[q] is equal X. There exists at least one q with best[q] non-negative, because there exist such a and b, a ≤ b, that xr[a-1] xor xr[b] = X.
The last step will be finding smallest possible q with non-negative best[q], which satisfies, that if there're more possible sequences, we should choose one with last cow having highest rank. The third condition, stating, that if there's still a tie we should choose shortest sequence, is satisfied thanks to the fact, that best[q] is always biggest possible.
这段话,这么个意思【逐句翻译太累,把重点挑出来】
【我们现在枚举到的指数是e】
我们维护个pop[n][2]:
xr[pop[q][0]]和xr[q]二进制[e,22]位都相等,且pop[q][0]是[0,q)中最大的,若找不到赋值-1
xr[pop[q][1]]和xr[q]二进制[e+1,22] 位都相等,且pop[q][0]是[0,q)中最大的,若找不到赋值-1
维护一个best[q]使得在目前情况中[best[q],q]异或的值满足可以达到的[e,22]最大赋值,且best[q]是[0,q)中最大的,若没有best[q]=-1
最后对所有q扫一遍best[q],得出答案
然后这三者怎么求……
我们对于一个best[q]与q,当我们枚举的这一指数e它们异或之后这一位不为1而是0,那么我们就需要考虑更新best[q],因为best[q]存的是xr[q]^xr[best[q]]的[e+1,22]最好结果【事实上也是答案的最好结果】那么我们要改变best[q],设best[q]的新值是y,这个新的xr[y]一定前[e+1,22]位与xr[best[q]]是相同的,这就是pop[q][1]的作用了
当然,如果e这一位无论如何也无法变成1,我们就跳过这一位
pop[q][0]辅助推出pop[q][1]
【别忘了看完这个做法之后下面还有一个很亲民的做法……】
【恭喜您已获得成就,翻译完USACO6.1的全部Analysis】qwq要是会的话还翻译什么Analysis辣
代码来一发【我的天吓死我了感谢博客园的恢复功能……】
/*
ID: ivorysi
LANG: C++
PROG: cowxor
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <algorithm>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
#define inf 0x5f5f5f5f
#define ivorysi
#define mo 97797977
#define hash 974711
#define base 47
#define fi first
#define se second
#define pii pair<int,int>
#define esp 1e-8
typedef long long ll;
using namespace std;
int pop[][],best[],a[],xr[],n,e,t;
int tmp[];
void solve() {
scanf("%d",&n);
siji(i,,n) {
scanf("%d",&a[i]);
xr[i]=xr[i-]^a[i];
best[i]=i-;
pop[i][]=i-;
pop[i][]=-;
}
pop[][]=-;pop[][]=-;best[]=-;
e=;
bool one;
while(e--) {
siji(i,,n) {
if(pop[i][]==-) {
pop[i][]=-;
}
else {
if(xr[pop[i][]] >> e != xr[i] >> e) {
tmp[]=pop[pop[i][]][];
/*pop[pop[i][0]]已经计算好了,
xr[pop[pop[i][0]][1]]的[e+1,22]与xr[pop[i][0]]相同
第e位不同,然而现在这种情况正好需要第e位与xr[pop[i][0]]不同
*/
tmp[]=pop[i][];
/*
正好满足前[e+1,22]位相同,第e位不同
*/
}
else {
tmp[]=pop[i][];
/*
正好满足前[e,22]位相同
*/
tmp[]=pop[pop[i][]][];
/*pop[pop[i][0]]已经计算好了,
xr[pop[pop[i][0]][1]]的[e+1,22]与xr[pop[i][0]]相同
第e位不同,然而现在这种情况正好需要第e位与xr[pop[i][0]]不同
*/
}
pop[i][]=tmp[];
pop[i][]=tmp[];
}
}
one=false;
siji(i,,n) {
if(best[i]>=) {
if((xr[best[i]]>>e)% != (xr[i]>>e)% || pop[best[i]][]>=) {
/*
如果e位不相同或者还可以找到更新的说明e位可以为1
*/
one=true;break;
}
}
}
if(one) {
siji(i,,n) {
if(best[i]>=) {
if((xr[best[i]]>>e)% == (xr[i]>>e)%) {
best[i]=pop[best[i]][];
}
}
} }
}
for(t=;best[t]<;++t);
printf("%d %d %d\n",xr[t]^xr[best[t]],best[t]+,t);
}
int main(int argc, char const *argv[])
{
#ifdef ivorysi
freopen("cowxor.in","r",stdin);
freopen("cowxor.out","w",stdout);
#else
freopen("f1.in","r",stdin);
#endif
solve();
return ;
}
第二个做法是我们建一棵01的trie树,插入每一个前缀和,从第21位到第1位
那么我们就可以每次贪心地去查前缀,如果这一位是0我们就尝试往1查,如果这一位是1我们就尝试往0查
由于USACO的空间很小,所以动态建一棵树……
/*
ID: ivorysi
LANG: C++
PROG: cowxor
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <algorithm>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
#define inf 0x5f5f5f5f
#define ivorysi
#define mo 97797977
#define hash 974711
#define base 47
#define fi first
#define se second
#define pii pair<int,int>
#define esp 1e-8
typedef long long ll;
using namespace std;
struct node {
node *son[];
int end;
node() {
memset(son,,sizeof(son));
end=;
}
}*root;
int n,a[];
int sum[];
int s,t,ans,x;
void ins(int val,int id) {
node *p=root;
gongzi(i,,) {
x=(val>>i)&;
if(p->son[x]==)
p->son[x]=new node;
p=p->son[x];
}
p->end=max(p->end,id);
}
int calc(int val) {
node *p=root;
gongzi(i,,) {
x=((val>>i)&)^;
if(p->son[x]!=) {
p=p->son[x];
}
else {
p=p->son[x^];
}
}
return p->end;
}
void solve() {
scanf("%d",&n);
siji(i,,n) scanf("%d",&a[i]);
sum[]=;
root=new node;
ins(sum[],);
ans=-;
int pos;
siji(i,,n) {
sum[i]=sum[i-]^a[i];
pos=calc(sum[i]); if((sum[i]^sum[pos])> ans) {
ans=sum[i]^sum[pos];
s=pos+;t=i;
}
ins(sum[i],i);
}
printf("%d %d %d\n",ans,s,t);
}
int main(int argc, char const *argv[])
{
#ifdef ivorysi
freopen("cowxor.in","r",stdin);
freopen("cowxor.out","w",stdout);
#else
freopen("f1.in","r",stdin);
#endif
solve();
return ;
}