Codeforces 1720 D, E

D1
dp(i)表示考虑前i个数的最长子序列。枚举j,从dp(j)+1转移到dp(i),转移条件就是题中给的那个不等式。

发现ij不能超过300,暴力枚举即可。

时间复杂度O(300n)

D2
dp(j)能转移到dp(i),当且仅当:aji<aij。若这个不等式成立,那么一定是二进制从大往小的前k位满足aji=aij,并且第(k+1)位满足aji=0,aij=1

aji=aij可以移项(注意异或的自反律仅用于等式,不能用于不等式,所以对于原式,我们没法移项),可得:aii=ajj

那么我们可以将aii作为关键字,放到Trie上。并且记录cnt(pos,x,y),表示子树pos中,i的第k位为xai的第k位为y时的最大DP值。找到最优转移只需枚举我们是哪一位出现不同数位的,设这一位为kik位为xaik位为y。由aji=0,aij=1,可知要满足aj的第k位和i相同,ai的第k位和j不同,也就是cnt(pos,y1,x)

时间复杂度O(nlogA)Aa的最大取值。

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=300005,maxm=300005*32;
int n,ans,a[maxn],f[maxn];
int cur,root,lef[maxm],rig[maxm],cnt[maxm][2][2];

int add() {
	++cur; lef[cur]=rig[cur]=0;
	memset(cnt[cur],0,sizeof cnt[cur]);
	return cur;
}

void insert(int pos,int dig,int key,int id,int dpval) {
	if(dig<0) return;
	int x=(id&(1<<dig))?1:0,y=(a[id]&(1<<dig))?1:0;
	cnt[pos][x][y]=std::max(cnt[pos][x][y],dpval);
	if(key&(1<<dig)) {
		if(!rig[pos]) rig[pos]=add();
		insert(rig[pos],dig-1,key,id,dpval);
	} else {
		if(!lef[pos]) lef[pos]=add();
		insert(lef[pos],dig-1,key,id,dpval);
	}
}

int query(int pos,int dig,int key,int id) {
	if(dig<0) return 0;
	int x=(id&(1<<dig))?1:0,y=(a[id]&(1<<dig))?1:0;
	int ret=cnt[pos][y^1][x];
	if((key&(1<<dig))&&rig[pos]) ret=std::max(ret,query(rig[pos],dig-1,key,id));
	if(!(key&(1<<dig))&&lef[pos]) ret=std::max(ret,query(lef[pos],dig-1,key,id));
	return ret;
}

void solve() {
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	cur=ans=0; root=add();
	for(int i=0;i<n;i++) {
		f[i]=query(root,30,i^a[i],i)+1;
		ans=std::max(ans,f[i]);
		insert(root,30,i^a[i],i,f[i]);		
	}
	printf("%d\n",ans);
	return;
}

int main() {
	int T; scanf("%d",&T);
	while(T--) solve();
	return 0;
}
posted @   Nastia  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示