bzoj1411: [ZJOI2009]硬币游戏 找规律神题

来源:互联网 发布:奇爱博士 知乎 编辑:程序博客网 时间:2024/05/23 01:38

Time Limit: 10 Sec Memory Limit: 162 MB

Description
Orez很喜欢玩游戏,他最近发明了一款硬币游戏。他在桌子的边缘上划分出2*n个位置并按顺时针把它们标号为1,2,……,2n,然后把n个硬币放在标号为奇数的位置上。接下来每次按如下操作:在任意两个硬币之间放上一个硬币,然后将原来的硬币拿走;所放硬币的正反面由它两边的两个硬币决定,若两个硬币均为正面朝上或反面朝上,则所放硬币为正面朝上,否则为反面朝上。 那么操作T次之后桌子边缘上硬币的情况会是怎样的呢?

Input
文件的第一行包含两个整数n和T。 接下的一行包含n个整数,表示最开始桌面边缘的硬币摆放情况,第i个整数ai表示第i个硬币摆放在2*i-1个位置上,ai=1表示正面朝上,ai=2表示反面朝上。

Output
文件仅包含一行,为2n个整数,其中第i个整数bi桌面边缘的第i个位置上硬币的情况,bi=1表示正面朝上,bi=2表示反面朝上,bi=0表示没有硬币。

Sample Input

10 5

2 2 2 1 1 1 1 1 1 2

Sample Output

0 1 0 1 0 1 0 1 0 2 0 1 0 2 0 1 0 1 0 1

数据范围

30%的数据 n≤1000 T≤1000

100%的数据 n≤100000 T≤2^60

这题一拿到就感觉是个神题,然后各种乱搞,各种画。
然后每个硬币经过2^k次变换后状态只与它左右第k+1个硬币有关系。然后就乱搞就好。

#include <cstdio>#include <algorithm>#include <iostream>using namespace std;const int MAXN = 200003;int a[MAXN], b[MAXN];long long n, T, m;long long l, r;int work(long long x, long long y) {    l = (x - y) % m + m;    l = l % m;    r = (x + y) % m;    if(a[l] == 0) return 0;    if(a[l] == a[r]) return 1;    return 2;}void solve(long long k, long long c) {    if(!k) return;    solve(k / 2, c << 1);    if(!(k % 2)) return;    for(int i = 1; i <= (int)m; i++) b[i] = work((long long)i, c);    swap(a, b);}int main() {    cin>>n>>T;    m = n << 1;    for(int i = 1; i <= (int)n; i++) cin>>a[i * 2 - 1];    solve(T, 1);    for(int i = 1; i <= (int)m; i++) {        cout<<a[i];        if(i != m) putchar(' ');        else putchar('\n');    }    return 0;}
0 0