Xor sum HDU - 6955
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xor sum HDU - 6955相关的知识,希望对你有一定的参考价值。
题意:
给定一个长度为n的整数序列,求其XOR和不小于k的最短连续子序列。
如果有多个相同长度的连续子序列,则打印具有最小左端点的连续子序列。
如果没有连续的子序列开关XOR总和不小于k,只需打印“-1”。
题解:
有关01串且求异或值相关内容,一般都用01字典树,本题也不例外
本题如何维护字典树呢?
我们先求出所有的前缀异或和[1,P],当前在Q的位置,我们寻找一个离Q最近的一个数,使得Q ^ P>=K。每次查询时,(此时字典树中只插入了Q之前的所有前缀异或和),都会从字典数的高位枚举到低位,如果K的第J位是1,为了保证Q ^ P>=K,Q ^ P的值也必须是1,那么P和Q的第J位就要不同,也就是我们要向Q的第J位相反的方向寻找,即 c = (Q>>j)&1寻找nxt[now][c ^ 1]。
如果K的第J位是0,此时Q^P的第J位可以是0或1,如果是1后面就不用比较了,已经大于K了,所以如果有1,即nxt[now][c ^ 1]存在,我们就记录最大的flag[],然后我们要向net[now][c]的方向寻找。为什么?先讲下flag[]表示的该异或值出现位置的最后的一次位置,也就是flag的值会尽可能靠近Q,这样才会让区间最小。我们在插入时维护flag,使得每个点都有最大的flag,当上面说的nxt[now][c ^ 1],此时K的第J位是0,我们不用再去走1这条路,因为已经比K大了,后面的也一定大于K,所以取最大flag即可,但是如果net[now][c]还是要继续走,因为目前还不知道是否大于等于K
(讲的有些乱,可以看看代码,代码很清晰)
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;
//qdu打铁匠
const ll INF=0x3f3f3f3f;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
const int maxn=1e7;
ll nex[maxn][3], cnt=0;
ll flag[210000000];
ll k;
struct trie
{
void insert(ll x,ll pos)
{
int p =0;
for(int i=29; i>=0; i--)
{
ll c=((x>>i)&1);
if (!nex[p][c])
{
nex[p][c] = ++cnt;
flag[cnt]=-1;
nex[cnt][1]=nex[cnt][0]=0;
} // 如果没有,就添加结点
p = nex[p][c];
flag[p]=max(flag[p],pos);
}
}
ll find(ll x)
{
ll ma=-1;
ll p=0;
for(int i=29; i>=0; i--)
{
ll c=((x>>i)&1);
ll ok=((k>>i)&1);
if(ok==0)
{
if(nex[p][c^1])
ma=max(ma,flag[nex[p][c^1]]);
p=nex[p][c];
}
else
{
p=nex[p][c^1];
}
if(p==0)
return ma;
}
return max(ma,flag[p]);
}
} tree;
ll a[1111111];
signed main()
{
ll t;
t=read();
while(t--)
{
ll n;
n=read();
k=read();
for(int i=1; i<=n; i++)
{
a[i]=read();
a[i]^=a[i-1];
}
for(int i=0; i<=cnt; i++)
{
nex[i][0]=0;
nex[i][1]=0;
flag[i]=0;
}
cnt=0;
ll ansl=0,ansr=n;
ll ma;
for(int i=1; i<=n; i++)
{
ma=-1;
ll x=tree.find(a[i]);
if(x!=-1)
{
ma=max(x,ma);
}
if(i-ma<ansr-ansl&&ma>0)
{
ansl=ma;
ansr=i;
}
tree.insert(a[i],i);
}
if(ansl>0)
{
printf("%d %d\\n",ansl+1,ansr);
}
else
{
printf("-1\\n");
}
}
}
以上是关于Xor sum HDU - 6955的主要内容,如果未能解决你的问题,请参考以下文章
2021杭州多校6955-xor sum(字典树+异或前缀和)