ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1720D2 题解

2022-08-27 13:31:16  阅读:154  来源: 互联网

标签:ch int 题解 pos CF1720D2 maxn bit oplus


前言

题目传送门!

更好的阅读体验?

感觉 D1 和 D2 不是同一个难度档次的呀......

思路

设 \(a_j\oplus i < a_i \oplus j\),这意味着数字 \(a_j\oplus i\) 中,从个位起前 \(k\) 位和 \(a_i \oplus j\) 相同,之后第 \(k+1\) 位就不同了。

两个不同下标的数有点难处理,考虑转化为同一个下标的数之间异或(例如 \(a_i \oplus i\))。

发现,如果 \(a_j\oplus i\) 和 \(a_i\oplus j\) 中的第 \(k\) 位相同,那么这些位在 \(a_j \oplus j\) 和 \(a_i \oplus i\) 也是相同的。

异或容易联想到 01 trie。考虑对 \(a_i \oplus i\) 拆位,每一位都添加到 trie 里。

可以先计算这个数的贡献值,然后在 trie 中一边插入,一边用这个贡献值更新答案。

发现 \(x \oplus y = 1\),肯定是 \(x = 0, y = 1\) 或者 \(x = 1, y = 0\)。

所以,这一位有贡献,当且仅当两个数位的值不同。因此这时,我们就在 trie 的另一边计算贡献。

差不多就这样了。需要注意,应该先计算贡献,再插入。

完整代码

#include <iostream>
#include <cstdio>
#define space putchar(' ')
#define endl putchar('\n')
using namespace std;
typedef long long LL;
typedef long double LD;
void fastio()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
}
LL read()
{
	char op = getchar(); LL x = 0, f = 1;
	while (op < 48 || op > 57) {if (op == '-') f = -1; op = getchar();}
	while (48 <= op && op <= 57) x = (x << 1) + (x << 3) + (op ^ 48), op = getchar();
	return x * f;
}
void write(LL x)
{
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) write(x / 10);
	putchar(x % 10 + 48);
}
const int N = 3e5 + 5;
int a[N], n;
struct Trie
{
	int ch[N * 31][2], dp[N * 31][2], cur;
	void init() //多测不清空,爆零两行泪! 
	{
		for (int i = 0; i <= cur; i++)
			for (int j = 0; j <= 1; j++)
				ch[i][j] = dp[i][j] = 0;
		cur = 0;
	}
	#define bit(x) (bool)(x & (1 << j)) //求x二进制下的第j位
	#define upd(x, y) x = max(x, y) //x = max(x, y)
	
	int getDP(int i) //i表示下标 
	{
		int x = a[i] ^ i, pos = 0;
		int maxn = 0; //用于更新dp
		for (int j = 30; j >= 0; j--)
		{
			//printf("bit = %d.\n", bit(x));
			if (ch[pos][!bit(x)]) upd(maxn, dp[ch[pos][!bit(x)]][!bit(a[i])]); //数位不同,异或才有贡献
			if (ch[pos][bit(x)]) pos = ch[pos][bit(x)];
			else break; //有就继续往下upd maxn,没有就停止 
		}
		return maxn;
	}
	void insert(int i, int maxn) //使用maxn更新字典树与dp 
	{
		int x = a[i] ^ i, pos = 0;
		for (int j = 30; j >= 0; j--)
		{
			if (!ch[pos][bit(x)]) ch[pos][bit(x)] = ++cur; //字典树基本操作
			upd(dp[ch[pos][bit(x)]][bit(i)], maxn);
			pos = ch[pos][bit(x)];
		}
	}
}trie;
void solve()
{
	trie.init();
	int n = read();
	for (int i = 0; i < n; i++) a[i] = read(); //题目要求下标从0开始。 
	int maxn = -2147483647; //最终的答案
	for (int i = 0; i < n; i++)
	{
		int mx = trie.getDP(i) + 1;
		upd(maxn, mx);
		trie.insert(i, mx);
	}
	write(maxn), endl;
}
int main()
{
	int T = read();
	while (T--) solve();
	return 0;
}

希望能帮助到大家!
首发:2022-08-24 17:00:47

标签:ch,int,题解,pos,CF1720D2,maxn,bit,oplus
来源: https://www.cnblogs.com/liangbowen/p/16622913.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有