Acwing 1960. 闪烁
农夫约翰对牛棚里昏暗的灯光感到不满,刚刚安装了一个新吊灯。
新吊灯由 NN 个灯泡组成,这 NN 个灯泡围成一圈,编号为 0∼N−10∼N−1。
奶牛对这个新吊灯非常着迷,并且喜欢玩以下游戏:
对于第 ii 个灯泡,如果在 T−1T−1 时刻,它左侧的灯泡(当 i>0i>0 时,为第 i−1i−1 个灯泡;当 i=0i=0 时,为第 N−1N−1 个灯泡)是开着,那么在 TT 时刻,就切换这个灯泡的状态。
这个游戏将持续 BB 单位时间。
给定灯泡的初始状态,请确定在 BB 单位时间后,它们的最终状态。
输入格式
第一行包含两个整数 NN 和 BB。
接下来 NN 行,按顺序描述每个灯泡的初始状态,每行包含一个整数 11 (表示开)或 00(表示关)。
输出格式
共 NN 行,按顺序每行输出一个灯泡的最终状态。
数据范围
3≤N≤163≤N≤16,
1≤B≤1015输入样例:
5 6
1
0
0
0
0
输出样例:
1
1
1
0
1
输入样例:
5 6
1
0
0
0
0
样例解释
灯泡状态如下:
时刻 T=0: 1 0 0 0 0
时刻 T=1: 1 1 0 0 0
时刻 T=2: 1 0 1 0 0
时刻 T=3: 1 1 1 1 0
时刻 T=4: 1 0 0 0 1
时刻 T=5: 0 1 0 0 1
时刻 T=6: 1 1 1 0 1
code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1<<16;//2^16
int n;
ll m;
int p[N];
int update(int state){
int res=0;
for(int i=0;i<n;i++){
int j=(i-1+n)%n;//找到前一位
int x=state >>i&1,y=state>>j &1;
res |=(x^y)<<i; //^是按位异或 |=按位或
}
return res;
}
void print(int state){
for(int i=0;i<n;i++){
cout<<(state>>i &1)<<endl;
}
}
int main(){
cin>>n>>m;
int state=0;
for(int i=0;i<n;i++){
int x;
cin>>x;
state |= x<<i;
}
memset(p,-1,sizeof p );
p[state]=0;
for(int i=1;;i++){
state=update(state);
if(i==m){//如果是最后一次更新
print(state);
break;
}
else if(p[state]==-1) p[state]=i;//更新当前状态是第几个状态
else{//如果出现了循环
int len =i -p[state];//更新的环的长度
int r=(m-i)%len;//还需要多少次更新
while(r--) state=update(state);
print(state);//把十进制数按照要求输出
break;
}
}
return 0;
}
解析
暴力求解肯定是行不通的,10^15次状态改变,必定超时。
这里主要的关键点是:
- 每一位的下一种状态等于与前一位的异或值
- 最多只有2^16=65536种状态,超过肯定会形成环
- 二进制数用十进制来存,与用string相比可以节约内存