HDU 6129 Just do it (机智)

Description

给出一个长度为\(n\)的非负整数数组\(a\),令\(b\)数组为\(a\)数组的前缀异或和,即\(b_i=a_1 \oplus a_2 \oplus \cdots \oplus a_i\),这样做\(m\)次,输出最终的\(b\)数组。

Input

第一行给出用例组数\(T\),对于每组用例,第一行给出\(n\)\(m\),第二行给出\(n\)个非负整数表示\(a\)数组。\(1 \leqslant n \leqslant 2 \times 10^5\)\(1 \leqslant m \leqslant 10^9\)

Output

对于每组用例,除数\(n\)个整数,表示求\(m\)遍异或和之后的\(b\)数组。

Sample Input

2
1 1
1
3 3
1 2 3

Sample Output

1
1 3 1

Solution

观察求每一遍异或前缀和后一个\(a_i\)\(b_j\)的贡献,发现每一个\(a_i\)贡献的数量构成杨辉三角,进一步总结后得出,求第\(m\)次异或前缀和后,\(a_i\)\(b_j\)贡献的数量为\(C(m+j-i-1,j-i)\)\(j \leqslant i\),即关于\(j-i\)的一个二项式系数,因为我们只关注二项式系数的奇偶性,有一个结论,\(C(a,b)\)是奇数当且仅当\(b\)的二进制表示中左右\(1\)的位置是\(a\)的二进制表示中所有\(1\)的位置的子集,即\(a\ and\ b = b\)。于是我们枚举\(j-i\)的值,记为\(k\),从\(0\)\(n-1\),仅当\(C(m+k-1,k)\)为奇数时更新\(b\)数组,为奇数的二项式系数并不多,可以在时间限制内完成。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;

int a[N], b[N];

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++) scanf("%d", a + i);
		memset(b, 0, sizeof(b));
		for (int k = 0; k < n; k++)
			if ((k & m + k - 1) == k)
                for (int i = 1; i + k <= n; i++) 
                    b[i + k] ^= a[i];
		for (int i = 1; i < n; i++) printf("%d ", b[i]);
		printf("%d\n", b[n]);
	}
	return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6129

posted @ 2017-08-15 20:58  达达Mr_X  阅读(223)  评论(0编辑  收藏  举报