bzoj1411: [ZJOI2009]硬幣遊戲

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

思路

思路1

我們可以先用O(mn)的模來做一做,之後可以發現每過2^k次方後,每個硬幣都有規律的,我們就可以這樣相當於拆一下二進制就可以了。

思路2

我們只考慮偶數的行,易知第二行每個數是原序列該位置左右兩個數的異或
由數學歸納法可以 第2^k行每個數是原序列該位置左側第2^(k-1)個數和右側第2^(k-1)個數的異或
然後將T進行二進制拆分,每位進行一次變換即可 最後再討論T的奇偶
時間複雜度O(n*logT)

ps:這題有毒,最後沒有空格,我第一次就輸出了空格結果PE了
ps:還有,在位運算時要把1變成long long否則會炸
哎~~,害得我這題三遍才過
這裏寫圖片描述

代碼

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int ret=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    while(c>='0'&&c<='9')ret=ret*10+c-'0',c=getchar();
    return ret*f;
}
int n,T,a[200005],b[200005];
#undef int 
int main(){
#define int long long
    n=read();T=read();
    for(int i=1;i<=n;++i)a[i*2-1]=read();
    if(T&1){
        for(int i=1;i<n;++i)a[2*i]=(a[2*i-1]!=a[2*i+1])+1;
        a[2*n]=(a[1]!=a[2*n-1])+1;
        for(int i=1;i<=n;++i)a[2*i-1]=0;
        --T;
    }
    for(int i=1;i<=62;++i){
        if(!((T>>i)&1))continue;
        for(int j=1;j<=2*n;++j){
            if(!a[j])continue;
            int l=(j-((int)1<<i))%(2*n);
            l=(l+i*2*n)%(2*n);
            if(!l)l=2*n;
            int r=(j+((int)1<<i))%(2*n);
            if(!r)r=2*n;
            b[j]=(a[l]!=a[r])+1;
        }
        for(int j=1;j<=2*n;++j)a[j]=b[j];
    }
    for(int i=1;i<2*n;++i)printf("%lld ",a[i]);
    printf("%lld",a[2*n]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章