6.28 CW 模拟赛 T1. 致敬传奇捆绑测试题目
前言
你说的对, 但是系统卡顿为啥可以用更新显卡驱动解决啊, 太猎奇了
心态, 停滞, 策略
哎我管你这那的
思路
首先考虑这个问题
要求任意一个数之前的前缀和大于这个数的排列中, 字典序最小的
打个表看下性质
发现性质最轻松的一集, 不难发现 \(a_1\) 是 \([1]\), \(a_2\) 是 \([2, 1]\), 此后 \(a_l = [3, 1, 2, 4, 5 \cdots l - 1, l]\), 不可能存在更小的 \(a_l\) 了
现在考虑原问题
我们现在要求
\[ \begin{align*}
& \bigoplus_{l = 1}^{n} \bigoplus_{i = 1}^{l} (a_{l, i} + i) \\
=& \bigoplus_{l = 4}^{n} \left(2 \oplus \bigoplus_{i = 4}^{l} 2i\right) \\
=& \Big([2 \nmid (n - 4 + 1)] \times 2\Big) \oplus \bigoplus_{l = 4}^{n}\bigoplus_{i = 4}^{l} 2i \\
=& \Big([2 \nmid (n - 4 + 1)] \times 2\Big) \oplus \bigoplus_{i = 4}^{n} \Big([2 \nmid (n - i + 1)] \times 2i\Big)
\end{align*} \]
\(n \leq 10^{18}\), 还不够
考虑异或操作的性质, 不难发现我们可以拆位计算, 现在的问题是
\[2n \oplus 2(n - 2) \oplus \cdots \oplus 4/5
\]
中, 位 \(i\) 出现了多少次
一个数 \(x\) 的位 \(i\) 为 \(1\), 当且仅当 \(\lfloor x/2^i \rfloor\) 为奇数
这个咋统计啊
考虑另外一种性质
不难发现类似十进制转二进制的方法, 我们每次只需要考虑当前的奇偶性, 然后对它除以 \(2\) 向下取整即可
依据这个性质, 不难发现会以 \(-1-2-4-8-\cdots\) 的形式出现数字变为 \(0\), 总的轮数显然是 \(\log n\) 级别的, 完全可以接受
我们大概画一个图来展现这个过程

每次点的数量和奇偶点的数量都很好计算, 按需统计异或和即可
代码
#include <bits/stdc++.h>
#define int long long
#define ever ;;
signed main() {
int n; scanf("%lld", &n);
int res = 0;
if (n == 1) { printf("2"); return 0; }
if (n == 2) { printf("2"); return 0; }
if ((n - 3) % 2) res = 2;
int ans = 0;
// for (int i = 4; i <= n; i++) {
// if ((n - i + 1) % 2) res ^= 2 * i;
// }
int begin = (n % 2) ? 5 : 4;
int len = n / 2 - 1;
int turn = -1;
int del = 0; // 打个补丁, 懒了
for (ever) {
// std::cout << len << '\n';
if (len <= 0) { ans ^= (del % 2) << (turn + 2); break; }
if (turn == -1) { if (begin % 2) ans ^= ((len % 2) << (turn + 2)); }
else {
int cir = 1ll << turn, num = len / cir;
int time = (num / 2 * cir) + ((num % 2 == 1) * (len % cir)) + del;
ans ^= (time % 2) << (turn + 2);
}
turn++;
if (turn) del = std::min(1ll << turn, len), len -= (1ll << turn);
}
printf("%lld", res ^ ans);
return 0;
}
总结
做出这个题比较关键的一点是打表?
大概就是你啥都不会的时候一定要动起来
异或特有的拆位, 不管了


浙公网安备 33010602011771号