杭電 F . Xor sum (字典樹)
阿新 • • 發佈:2021-07-25
題意:
給出n個數,找到最短的區間異或和大於等於K 若沒有則輸出" - 1 "
思路:
首先我們維護出來異或字首,我們知道[l~r]的異或字首等於[ 1 ~ r ] ^ [1 ~ (l - 1) ]這個與字首和有些相似。
然後我們用字典樹維護出來這個字首,通過記錄節點的下表,寫算出區間長度。
ll n,k,tot; ll tree[maxn][2]; ll cnt[maxn]; ll a[maxn]; void insert(ll x,ll num){ ll pos=0,tmp; for(int i=31;i>=0;i--){ tmp=x>>i &1; if(!tree[pos][tmp]){ tree[pos][tmp] =++tot; } pos=tree[pos][tmp]; cnt[pos] = max(cnt[pos],num); } } ll search(ll x){ ll top=0; ll tmpx,tmpk; ll l=0; for(int i=31;i>=0;i--){ tmpx=x>>i&1; tmpk=k>>i&1; if(tmpx){///1 if(tmpk){///1 if(!tree[top][0]) return l; top=tree[top][0]; } else { l=max(l,cnt[tree[top][0]]); if(!tree[top][1])return l; top=tree[top][1]; } }else { if(tmpk) { if(!tree[top][1]) return l; top=tree[top][1]; }else { l=max(l,cnt[tree[top][1]]); if(!tree[top][0]) return l; top=tree[top][0]; } } } return l=max(l,cnt[top]); } void solve() { scanf("%lld%lld",&n,&k); for(int i=0;i<=tot;i++){ tree[i][0]=tree[i][1]=0; cnt[i]=0; } tot=0; for(int i=1;i<=n;i++){ cin>>a[i]; a[i]=a[i-1]^a[i]; } ll ans=1e18; ll ansl = 0,ansr=0; insert(0,0); for(int i=1;i<=n;i++){ int l = search(a[i]); if(l&&i-l<ans){ ans=i-l; ansl=l+1; ansr=i; } insert(a[i],i); } if(ans==1e18) puts("-1"); else printf("%lld %lld\n",ansl,ansr); }