[ZJOI2009] 硬币游戏(找规律)

题目

洛谷传送门

题解

1 / 2 1/2 转化成 0 / 1 0/1 ,所以直接可以异或。

对于长度为 n n 0 / 1 0/1 数列,发现每变换 2 k ( k > 1 ) 2^k(k>1) 时,且每个数的值就是往左和往右各走2^(k-1)步的值异或起来

那么把 m m 二进制分解一下,最后如果是奇数就多做一次。

CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
const int LOG = 65;
LL pw[LOG], m;
int n, a[2][MAXN];
int main () {
	pw[0] = 1; for(int i = 1; i <= 60; ++i) pw[i] = pw[i-1] * 2;
	scanf("%d%lld", &n, &m);
	for(int i = 0; i < n; ++i) scanf("%d", &a[0][i]), --a[0][i];
	int cur = 0;
	for(int i = 60; i >= 1; --i)
		if(m>>i&1) {
			cur ^= 1;
			for(int j = 0; j < n; ++j)
				a[cur][j] = a[cur^1][(j-pw[i-1]%n+n)%n] ^ a[cur^1][(j+pw[i-1]%n)%n];
		}
	if(m&1) {
		cur ^= 1;
		for(int j = 0; j < n; ++j)
			a[cur][j] = a[cur^1][j] ^ a[cur^1][(j+1)%n];
		for(int i = 0; i < n; ++i)
			printf("0 %d%c", a[cur][i]+1, " \n"[i==n-1]);
	}
	else {
		for(int i = 0; i < n; ++i)
			printf("%d 0%c", a[cur][i]+1, " \n"[i==n-1]);
	}
}
发布了367 篇原创文章 · 获赞 239 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Ike940067893/article/details/102823050