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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/12237050.html