巨魔没金币
题目描述
某巨魔去了一趟拍卖行卖东西,赚了不少金币,然后又买了些东西,就没金币了。
该巨魔没了金币,但他还有很多银币。
他搞了张圆桌。划分出
2∗N
个位置标号
1
到
接下来每次按如下操作:在任意两个银币之间放上一个银币,然后将原来的银币拿走;
所放银币的正反面由它两边的两个银币决定,若两个银币均为正面朝上或反面朝上,则所放银币为正面朝上,否则为反面朝上。
那么操作
输入格式
第一行包含两个整数
n
和
接下的一行包含
n
个整数,表示最开始桌面边缘的硬币摆放情况,第
输出格式
输出一行
2n
个整数,其中第
i
个整数
样例输入
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%
的数据:
1≤N≤1000
、
1≤T≤1000
。
100%
的数据:
1≤N≤100000
、
1≤T≤260
。
Solution
若将每一位上的数字减
1
,则可知一次操作对应两个数字求异或。
打表发现,进行
那么,我们可以将
Summary
考场上我是发现了
进行
2k 次操作后, i 位上的数字为i−2k 与 i+2k 上的数字的异或值(将 n 个数字向左、右无限复制)
的规律的。
但当时特别脑残,认为这个规律只能做一个特判,即
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;
}