1 条题解
-
0
自动搬运
来自洛谷,原作者为

C锥
AFO搬运于
2025-08-24 21:46:47,当前版本为作者最后更新于2020-09-03 21:08:42,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
九月四日 update:更改了错误的证明
我发现其他题解都是用记忆化,蒟蒻表示看不懂,这里提供一种预处理 值的代码。
首先我们要知道 定理: $ SG_{tot} = SG_1 \ xor \ SG_2\ xor \ SG_3 \ xor \ ... \ xor \ SG_n $ 。
这里地方太小,我施展不开,就不证明了。
(好吧太难了我不会)所以我们可以预处理出1到100000中每个数的 值,对于每一个询问,我们只需求一下 就好了。
那怎么预处理出每一个数的 值呢?
对于某一堆 ,有 个石子,我们可以枚举分成的堆数 。设分成 堆后, 每堆的石子个数为 , 我们求出 的异或和 ,就是分成 堆后的状态的 值,然后取 运算得出当前状态 的 值。
可这太暴力了,时间复杂度是 的,70分,考虑优化。
我们可以发现分成的 堆的石子数最多有两种取值,分别是: 。这两种取值的个数分别是: 。
再考虑有贡献的值,因为求的是 的异或和,所以只有某个取值的个数为奇数个时,才有贡献。接下来只需判断两种取值的个数的奇偶性就好了。
举个例子: 时
m : 2 3 4 5 6 7 8 9 i / m : 4 3 2 1 1 1 1 1可以发现 从5到9, 值是相同的,对于某些不同的 , 的值相同,就可以用整除分块做。我们把后面分的石子堆数都列出来:
5 : 2 2 2 2 1 6 : 2 2 2 1 1 1 7 : 2 2 1 1 1 1 1 8 : 2 1 1 1 1 1 1 1 9 : 1 1 1 1 1 1 1 1 1可以发现某一个数目的石子堆数的奇偶性是一定的,证明:
多举几个例子就好了当 为奇数时,$ \begin{aligned}m -i\%m = m - (i- m\times\lfloor \frac{i}{m}\rfloor)=m \times (1+\lfloor \frac{i}{m}\rfloor)-i\end{aligned} $,对于 $ \begin{aligned}1+\lfloor \frac{i}{m}\rfloor\end{aligned} $ 为偶数, 后,奇偶性不变
当 为偶数时,$ \begin{aligned}i\%m = i- m\times\lfloor \frac{i}{m}\rfloor\end{aligned} $,后,奇偶性不变 (感谢@Ame__ 的提醒qwq)
所以对于 相等的块内,分出的石子数的两种取值的奇偶性的组合只有两种(有点绕,好好想想),所以对于一整块内只需算出这两种不同的 异或和就好了,因为取 运算不需要判断重复的值。第一种和第二种一定可以算出所有不同的 异或和的值,算前两种就好了。
#include <bits/stdc++.h> using namespace std; inline long long read() { long long s = 0, f = 1; char ch; while(!isdigit(ch = getchar())) (ch == '-') && (f = -f); for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48)); return s * f; } const int N = 105, M = 1e5 + 5; int T, F, n; int a[N], SG[M], vis[N]; int main() { T = read(); F = read(); // 1 到 F-1 先手必输,SG数组的值为0 for(int i = F;i <= M - 5; i++) { int r; for(int j = 2;j <= i; j = r + 1) { int t = i / j; r = i / (i / j); int flag; if(j == r) flag = 1; // 如果i/m值相等的只有一个数,那就不需要算两遍了 else flag = 2; int num = 0, res = 0; while(num < flag) { num++; res = 0; if((i % j) & 1) res ^= SG[t + 1]; if((j - i % j) & 1) res ^= SG[t]; j++; vis[res] = i; } } for(int j = 0; ; j++) if(vis[j] != i) { SG[i] = j; break; } } while(T --> 0) { n = read(); int res = 0; for(int i = 1;i <= n; i++) { a[i] = read(); res ^= SG[a[i]]; } if(res == 0) printf("0 "); else printf("1 "); } return 0; }(如果哪有不对的还请dalao指正)
- 1
信息
- ID
- 2308
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者