D2. Xor-Subsequence (hard version)

D2. Xor-Subsequence (hard version)

昨天cf的E题,挺好的一个DP优化问题。
暴力的DP就是设dp[i]表示以i结尾的最长长度。转移时枚举之前的所有j,复杂度O(n^2)。
考虑怎么优化,优化往往都是从转移条件上做文章的,我们考虑当前i的dp值怎么计算,
是所有max(f[j]+1),而且这些j满足aixorj<ajxori。
左边小于右边,又与异或有关,所以考虑二进制,在二进制下,一定满足一个k,使得从高到底数,前k-1位两者都相等,第k位右边为1,左边为0.那么倘若我们只考虑这前k-1位的话,可以发现aixorj=ajxori,则aixorjxorajxori=0.可得aixori=ajxorj。(终于将i和j分开了...因为在dp优化问题中,我们尽量使得j和i没关系,这样的话方便我们进行操作。)至于第k位,由于我们知道i和ai的信息,所以j和aj在这一位上是0还是1就确定了。至此我们考虑用什么样的一个数据结构去优化这个过程。
tire树,因为我们看到aixori和ajxorj相等,tire树正好可以实现这个操作,并且我们在插入的过程中完全可以维护i和a[i]这一位上位0还是1的信息。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,M=1e7+10;
int T,n,a[N],tire[M][2],f[M][2][2],dp[N],tot;
//f[x][0/1][0/1]表示x及其之前的都相等,x下一位开始,i为0/1,a[i]为0/1的dp最大值. 
inline int query(int id,int val)
{
	int p=1,ans=0;
	for(int i=30;i>=0;--i)
	{
		int c2=(val&(1<<i))?0:1,c1=(id&(1<<i))?1:0;
		ans=max(ans,f[p][c2][c1]); 
		int ch=((id^val)&(1<<i))?1:0;
		if(!tire[p][ch]) break;
		p=tire[p][ch];
	}
	return ans;
}
inline void insert(int id,int val)
{
	int p=1;
	for(int i=30;i>=0;--i)
	{
		int c2=(val&(1<<i))?1:0,c1=(id&(1<<i))?1:0;
		f[p][c1][c2]=max(f[p][c1][c2],dp[id]);
		int ch=((id^val)&(1<<i))?1:0;
		if(!tire[p][ch]) tire[p][ch]=++tot;
		p=tire[p][ch];
	} 
}
inline void solve()
{
	cin>>n;
	for(int i=0;i<n;++i) cin>>a[i];
	tot=1;
	int ans=0;
	for(int i=0;i<n;++i)
	{
		int temp=query(i,a[i]);
		dp[i]=temp+1;
		insert(i,a[i]);
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
	for(int i=1;i<=tot;++i)
		for(int j=0;j<2;++j)
		{
			tire[i][j]=0;
			for(int k=0;k<2;++k) f[i][j][k]=0;
		}		 
}
int main()
{
//	freopen("1.in","r",stdin);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--) solve();
	return 0;
}
posted @ 2022-08-19 15:23  逆天峰  阅读(174)  评论(0编辑  收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//