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;		
}
posted @ 2019-09-02 15:09  四季夏目天下第一  阅读(148)  评论(0编辑  收藏  举报