8.29 我们自己的世界
题意
给一个大小为\(N\)的数组\(A\),每次对数组进行如下的变换:
- \(B[i]=A[i]\oplus A[i+1]\)
- \(A[i]=B[i]\)
这里的\(\oplus\)运算指异或
我们会发现每次数组\(A\)的长度会减一,当数组\(A\)的长度减至一时,结束变换
如果我们把每次变换后的\(A\)数组的第一项保存下来,记为\(A_0[1],A_1[1]...A_{n-1}[1]\)
求
\[\oplus \sum_{i=0}^{n-1}A_i[1] \times (i+1)
\]
这里的\(\oplus \sum\)指的是异或和运算
\(N \leq 8\times 10^6\)
解法
这题解法巨巧妙
画出一个类似菱形网格图的结构,观察一下每次变换后的第一项是被哪些元素异或几次组成的
把元素编号由\(1,2..n\)改为\(0,1...n-1\)
我们能观察到如下的规律
变换\(/\)元素 | \(a_0\) | $a_1 $ | $a_2 $ | \(...\) | \(a_{n-1}\) |
---|---|---|---|---|---|
\(1\) | \(1\) | \(0\) | \(0\) | \(0\) | \(0\) |
\(2\) | \(1\) | \(2\) | \(1\) | \(0\) | \(0\) |
$... $ | |||||
\(n\) | \(C_n^0\) | \(C_n^1\) | \(C_n^2\) | \(...\) | \(C_n^{n-1}\) |
这不就是个杨辉三角吗?
我们知道,异或次数为奇数的有贡献,异或次数为偶数的无贡献
那么现在我们需要快速求出组合数的奇偶性
根据卢卡斯定理,我们知道
\[C_n^m \pmod p = C_{n\%p}^{m\%p} \times C_{n/p}^{m/p}
\]
现在我们需要判断其奇偶性,就需要模一个\(2\)
\[C_n^m \pmod 2 = C_{n\%2}^{m\%2} \times C_{n/2}^{m/2}
\]
我们可以把\(\%2\)与\(/2\)视作二进制位下的操作,即
\[C_n^m\pmod 2=C_{n\&1}^{m\&1}\times C_{n>>1}^{m>>1}
\]
研究一下\(C_{n\&1}^{m\&1}\)我们发现,只有\(n\)为偶数\(m\)为奇数时这个数为\(0\),其余均为\(1\)
也就是\(n\)的某一位为\(0\)而\(m\)的某一位为\(1\)时,这个数为\(0\)
所以我们可以发现
\[C_n^m \pmod 2 = 1 \ \ (m \& n=m)\\
C_n^m \pmod 2 = 0 \ \ (otherwise)
\]
所以当\(m\)为\(n\)的子集时,元素\(a_m\)会对第\(n\)次变换的第一个元素有贡献
设
\[b_n=\oplus \sum_{d\& n=n}a_d
\]
最后的答案即为
\[ans=\oplus \sum_{i=0}^{n-1} (i+1)\times b_i
\]
于是现在的问题转化为了求\(b\)数组,也就是对于数组\(a\)每个位置上求一遍子集和
这个可以用\(FWT\),但更方便的是采用\(FMT\),代码比较短
本质上就是做一个\(n\)维的前缀和,一维一维的累加答案
代码
#include <cstdio>
using namespace std;
const int N = 8e6 + 10;
int n;
long long a, b, c, d;
long long A[N];
int main() {
scanf("%d%lld%lld%lld%lld", &n, &a, &b, &c, &d);
A[0] = a;
for (int i = 1; i < n; ++i)
A[i] = (A[i - 1] * A[i - 1] % d + b * A[i - 1] % d + c) % d;
for (int i = 0; i < 23; ++i)
for (int j = 0; j < n; ++j)
if ((j >> i) & 1) A[j] ^= A[j ^ (1 << i)];
long long ans = 0;
for (int i = 0; i < n; ++i) ans ^= A[i] * (i + 1);
printf("%lld\n", ans);
return 0;
}