题意
给一个大小为(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] imes (i+1)
]
这里的(oplus sum)指的是异或和运算
(N leq 8 imes 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} imes C_{n/p}^{m/p}
]
现在我们需要判断其奇偶性,就需要模一个(2)
[C_n^m pmod 2 = C_{n\%2}^{m\%2} imes C_{n/2}^{m/2}
]
我们可以把(\%2)与(/2)视作二进制位下的操作,即
[C_n^mpmod 2=C_{n&1}^{m&1} imes 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) imes 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
", ans);
return 0;
}