巨魔沒金幣

巨魔沒金幣


題目描述

某巨魔去了一趟拍賣行賣東西,賺了不少金幣,然後又買了些東西,就沒金幣了。
該巨魔沒了金幣,但他還有很多銀幣。
他搞了張圓桌。劃分出 2N 個位置標號 12N ,然後把 N 個銀幣放在奇數位置上。
接下來每次按如下操作:在任意兩個銀幣之間放上一個銀幣,然後將原來的銀幣拿走;
所放銀幣的正反面由它兩邊的兩個銀幣決定,若兩個銀幣均爲正面朝上或反面朝上,則所放銀幣爲正面朝上,否則爲反面朝上。
那麼操作 T 次之後桌子邊緣上銀幣的情況會是怎樣的呢?


輸入格式

第一行包含兩個整數 nT
接下的一行包含 n 個整數,表示最開始桌面邊緣的硬幣擺放情況,第 i 個整數 ai 表示第 i 個硬幣擺放在 2i1 個位置上,ai=1 表示正面朝上,ai=2 表示反面朝上。


輸出格式

輸出一行 2n 個整數,其中第 i 個整數 bi 桌面邊緣的第 i 個位置上硬幣的情況,bi=1 表示正面朝上, bi=2 表示反面朝上,bi=0 表示沒有硬幣。


樣例輸入

10 5
2 2 2 1 1 1 1 1 1 2


樣例輸出

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


數據範圍

30% 的數據:1N10001T1000
100% 的數據:1N1000001T260


Solution

若將每一位上的數字減 1 ,則可知一次操作對應兩個數字求異或。
打表發現,進行 2k 次操作後, i 位上的數字爲 i2ki+2k 上的數字的異或值(將 n 個數字向左、右無限複製)。
那麼,我們可以將 T 分解爲 2 的冪之和,然後逐步求出答案。


Summary

考場上我是發現了

進行 2k 次操作後, i 位上的數字爲 i2ki+2k 上的數字的異或值(將 n 個數字向左、右無限複製)

的規律的。

但當時特別腦殘,認爲這個規律只能做一個特判,即 T2 的冪的情況……然後就棄療了。


Code

#include <iostream>
#include <cstdio>

#define LL long long

using namespace std;

LL n,t;
LL w[200010];
LL tot[200010];

void work(LL x){
    LL tmp=1;
    while(tmp<=x)tmp<<=1;
    tmp>>=1;
    while(x){
        while(tmp>x)tmp>>=1;
        for(int i=1;i<=2*n;i++){tot[i]=w[i];w[i]=-1;}
        if(tot[1]!=-1&&tmp==1||tot[1]==-1&&tmp!=1)
            for(int i=2;i<=2*n;i+=2){
                w[i]=tot[(((i-tmp)-1)%(2*n)+2*n)%(2*n)+1]^tot[((i+tmp)-1)%(2*n)+1];
            }
        else
            for(int i=1;i<=2*n;i+=2){
                w[i]=tot[(((i-tmp)-1)%(2*n)+2*n)%(2*n)+1]^tot[(((i+tmp)-1)%(2*n)+2*n)%(2*n)+1];
            }
        x-=tmp;
    }
}

int main(){

    freopen("silver.in","r",stdin);
    freopen("silver.out","w",stdout);

    scanf("%lld%lld",&n,&t);
    for(int i=1;i<=n;i++){
        w[2*i]=-1;
        scanf("%lld",&w[2*i-1]);
        w[2*i-1]--;
    }
    work(t);
    for(int i=1;i<=2*n;i++)printf("%d ",w[i]+1);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章