首页 > 其他分享 >Codeforces 1720 D, E

Codeforces 1720 D, E

时间:2022-08-20 23:24:07浏览次数:104  
标签:移项 pos 1720 Codeforces 枚举 oplus dp 位为

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

发现\(i-j\)不能超过\(300\),暴力枚举即可。

时间复杂度\(O(300n)\)。

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

对\(a_{j}\oplus i=a_{i}\oplus j\)可以移项(注意异或的自反律仅用于等式,不能用于不等式,所以对于原式,我们没法移项),可得:\(a_{i}\oplus i=a_{j}\oplus j\)。

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

时间复杂度\(O(n\log A)\),\(A\)为\(a\)的最大取值。

#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;
}

标签:移项,pos,1720,Codeforces,枚举,oplus,dp,位为
From: https://www.cnblogs.com/Nastia/p/16609023.html

相关文章

  • [题解] Codeforces 1720 E Misha and Paintings 结论
    算是诈骗题?令一开始就存在的颜色数为cnt。k>=cnt的情况,显然每次找一个出现不止一次的颜色,然后把这个颜色的恰好一个方块替换成一种没有出现过的颜色就可以了,\(k-cnt\)次解......
  • codeforces963D. Frequency of String【哈希】
    我的腿让我停下,可是我的心却不许我这么做今天又是为了明知多半不可能的事情奔波一早,一天里,出了很多丑,犯了很多错,见了很多人,有了很多意想不到的收获,我选择了我的生存方式......
  • Codeforces Round #815 (Div. 2) 题解
    CF1720A.BurenkaPlayswithFractions给出两个分数$\dfrac{a}{b}$和\(\dfrac{c}{d}\),你每次操作能够选择其中一个分数的分子或分母,将其乘上任意一个整数(当然不能......
  • Codeforces 杂题集
    本文主要把近期\(CF-Div.2\)的\(A,B,C,D\)题进行做Round815A题意给你两个分数\(\frac{a}{b},\frac{c}{d}\),问你最少几次使两个分数相等。Solution首先考虑,最......
  • Codeforces Round #815 (Div. 2) D2 Xor-Subsequence (hard version)
    原题链接\(A>B\),总是有二进制下从高到低的前\(k\)位相等,第\(k+1\)位\(A\)是\(1\),\(B\)是\(0\)本题中\(A=a_i\oplusj\),\(B=a_j\oplusi\),这里有一个很奇妙的性质(手玩或者......
  • CodeForces-1601B Frog Traveler
    FrogTravelerdp+bfs感觉又像搜索从后往前进行状态转移,像\(bfs\)一样保证当前搜索的是消耗次数最少的状态转移因为是一个连续的区间,因此考虑当前能上升到的最大距......
  • CodeForces-1671E Preorder
    Preorder树型dp+思维\(dp[i]\)表示以\(i\)为根的子树通过变换有多少种不同的先序遍历状态转移方程:当左右子树不同,两个子树交换位置之后,没有重复的出现:\(dp[x]......
  • Codeforces #815 Div.2
    A—BurenkaPlayswithFractions思路:数论O(1)见题解题解:#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;typedeflonglongL......
  • Educational Codeforces Round 117 (Rated for Div. 2) CF1612
    https://codeforces.com/contest/1612VP过了A~E,感觉海星。F,G这几天补。主要是luogu有翻译拯救了英语不好的我。A一眼\(x+y\equiv0\pmod{2}\),否则无解。那么显......
  • Educational Codeforces Round 33 (Rated for Div. 2) 虚拟赛体验
    前言就只做出了\(A,B,C,D\)是不是很弱?A.ChessForThreeA,B,C三人下棋,A和B先下,每次下完棋之后由现在观战的人(例如第一局就由C)代替下输的人。每次输入一个数表示谁赢......