CF1720D2 题解
2022/8/27 23:22:53
本文主要是介绍CF1720D2 题解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
题目传送门!
更好的阅读体验?
感觉 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
这篇关于CF1720D2 题解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享
- 2024-11-22ansible 的archive 参数是什么意思?-icode9专业技术文章分享
- 2024-11-22ansible 中怎么只用archive 排除某个目录?-icode9专业技术文章分享
- 2024-11-22exclude_path参数是什么作用?-icode9专业技术文章分享
- 2024-11-22微信开放平台第三方平台什么时候调用数据预拉取和数据周期性更新接口?-icode9专业技术文章分享
- 2024-11-22uniapp 实现聊天消息会话的列表功能怎么实现?-icode9专业技术文章分享
- 2024-11-22在Mac系统上将图片中的文字提取出来有哪些方法?-icode9专业技术文章分享
- 2024-11-22excel 表格中怎么固定一行显示不滚动?-icode9专业技术文章分享
- 2024-11-22怎么将 -rwxr-xr-x 修改为 drwxr-xr-x?-icode9专业技术文章分享
- 2024-11-22在Excel中怎么将小数向上取整到最接近的整数?-icode9专业技术文章分享