BZOJ 1411. [ZJOI2009]硬币游戏
题目老是没说清楚哇。。
把正面设为0,反面设为1,那么下一次得到的硬币就是左右两个硬币的异或和。
这种多次相邻进行异或的,大概就有个规律,多消几次能有规律。
模拟一下就发现,进行 $2^k$ 次操作之后,第 $i$ 个位置就是原序列 $i-2^k$ 和 $i+2^k$ 位置的异或和。
那么就对 $T$ 二进制拆分一下模拟着做就行了
#include <bits/stdc++.h> #define ll long long const int N = 2e5 + 7; int a[N], n, b[N]; ll T; void solve(ll dif) { for (int i = 1; i <= 2 * n; i += 2) { int left = ((i - dif) % (2 * n) + 2 * n) % (2 * n); int right = (i + dif) % (2 * n); if (!left) left = 2 * n; if (!right) right = 2 * n; b[i] = a[left] ^ a[right]; } for (int i = 1; i <= 2 * n; i++) a[i] = b[i], b[i] = 0; } int main() { scanf("%d%lld", &n, &T); for (int i = 1; i <= n; i++) { scanf("%d", &a[i * 2 - 1]); a[i * 2 - 1]--; } for (int i = 60; i; i--) { if (T >> i & 1) solve(1LL << i); } if (T & 1) { for (int i = 2; i <= 2 * n; i += 2) { int left = i - 1; int right = i + 1; if (right > 2 * n) right = 1; b[i] = a[left] ^ a[right]; } for (int i = 1; i <= 2 * n; i++) { int x = 0; if (i % 2 == 0) x = b[i] + 1; printf("%d%c", x, " \n"[i == 2 * n]); } return 0; } for (int i = 1; i <= 2 * n; i++) { int x = 0; if (i & 1) x = a[i] + 1; printf("%d%c", x, " \n"[i == 2 * n]); } return 0; }