0
点赞
收藏
分享

微信扫一扫

《每日一题》闪烁

若如初梘 2022-01-14 阅读 150
状态模式

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次状态改变,必定超时。

这里主要的关键点是:

  1. 每一位的下一种状态等于与前一位的异或值
  2. 最多只有2^16=65536种状态,超过肯定会形成环
  3. 二进制数用十进制来存,与用string相比可以节约内存

在这里插入图片描述
请添加图片描述

举报

相关推荐

0 条评论