01trie 的简单应用

· · 题解

讲的是 CF1720D2。

简要题意:

t 组数据,对于每组数据,给定 na_0,...,a_{n-1},均为自然数,求一个最长的自然数列 b_i,设其长度为 m 需要满足 0\le b_1<...<b_m<n\forall i\in[1,m),a_{b_i}\otimes b_{i+1}<a_{b_{i+1}}\otimes b_i

容易发现这是一个动态规划的模型,我们需要找到 $\max\limits_{j<i,a_j\otimes i<a_i\otimes j}f_j$,由于只有位运算,不难想到按位考虑。 从高到低考虑每一位,如果 $a_j\otimes i$ 和 $a_i\otimes j$ 在该位相同,这等价于 $a_j\otimes j$ 与 $a_i\otimes i$ 在该位相同,就继续下一位,否则一定是 $a_i\otimes j$ 在这一位为一。 将 $i$ 从小到大计算,在求出 $f_i$ 后,可以将 $a_i\otimes i$ 插入到一棵 $\text{01trie}$ 内,对于每一个节点记录 $i$ 在上一位为一的最大值,和为零的最大值。 查询就顺着 $a_i\otimes i$ 走 $\text{01trie}$,沿途处理相反方向的答案(即该位不同的情况)。 不到 1k 的 AC 代码: ```cpp #include<bits/stdc++.h> using namespace std; const int N=1e6+6; using ll=long long; ll A,B,C,D; ll T,n,m,f[N],a[N]; int t[N<<4][2],mx[N<<4][2],ans; inline void Mx(int &x,int y){if(x<y)x=y;} int cnt,rt,v1,v2,v3,nw; void ins(int &x,int w=31){ if(!x)x=++cnt; int p=v1^v2; Mx(mx[x][(v2>>w)&1],v3); if(w--)ins(t[x][(p>>w)&1],w); } void qry(int &x,int w=31){ if(x&&w--){ int k=((v1^v2)>>w)&1; Mx(nw,mx[t[x][!k]][((v1>>w)&1)^1]); qry(t[x][k],w); } } int main(){ int i,j,k,l,md,r; ios::sync_with_stdio(false); cin>>T;while(T--){ for(i=1;i<=cnt;++i) mx[i][0]=mx[i][1]=t[i][0]=t[i][1]=0; cin>>n,ans=cnt=rt=0; for(i=1;i<=n;++i)cin>>a[i]; for(i=1;i<=n;++i){ v1=a[i],v2=i-1,nw=0,qry(rt); Mx(ans,v3=f[i]=nw+1),ins(rt); }printf("%d\n",ans); }return 0; } ```