zhao_ry514114
赵若伊

导航

 

原题(P2203 Blink)

记录传送门

思路

由于B可能会超过一般的32位整数范围

暴力模拟肯定是不可行的

看到这种题我会有种题感

大概率是有循环节的

所以我们打一段表试试:

时刻T
初始 1 0 0 0 0
1 1 1 0 0 0
2 1 0 1 0 0
3 1 1 1 1 0
4 1 0 0 0 1
5 0 1 0 0 1
6 1 1 1 0 1
7 0 0 0 1 1
8 1 0 0 1 0
9 1 1 0 1 1
10 0 0 1 1 0
11 0 0 1 0 1
12 1 0 1 1 1
13 0 1 1 0 0
14 0 1 0 1 1
15 0 1 1 1 1
16 1 1 0 0 0
17 1 0 1 0 0

可以发现当T为1和为16时灯的状态是一样的

所以此样例下的循环节从1开始,长度为15

但不一定每个样例的循环节都一样,也不一定都从1开始

比如我们再举一个极端一点的例子:

当N为3,初始状态为010时

时刻T
初始 0 1 0 0
1 0 1 1 0
2 0 1 0 1
3 1 1 1 1
4 0 0 0 0
5 0 0 0 0
6 0 0 0 0
7 0 0 0 0

以上样例循环节从T为4开始,且长度为1

那么如何判断/查找循环节

直接枚举

用一个vector记录枚举出来的每一个结果

然后每次遍历一遍之前储存过的结果

如果有相同的结果,更早一点的那个结果的索引即为循环节起点,二者之间的距离即为循环节的长度

贴代码:

#include<bits/stdc++.h>
using namespace std;
vector<string>a;
int main(){
    long long n,b;
    cin>>n>>b;
    string s;
    for(int i=0;i<n;i++){
        char c;
        cin>>c;
        s+=c;
    }//初始状态储存
    a.push_back(s);
    int cnt=0;
    bool x=1;
    int len;
    int st=0;
    while(x){//找循环节
        string t="";
        for(int i=0;i<a[cnt].size();i++){
            if(a[cnt][(n+i-1)%n]=='1'){
                if(a[cnt][i]=='0'){
                    t+='1';
                }
                else t+='0';//灯的状态
            }
            else t+=a[cnt][i];
        }
        a.push_back(t);
        cnt++;//记录vector最大索引
        for(int i=0;i<cnt;i++){
            if(a[i]==t){//找到重复结果
                len=cnt-i;
                st=i;
                x=0;
            }
        }
    }
    string t=a[st+(b-st)%len];
    for(int i=0;i<t.size();i++){
        cout<<t[i]<<endl;
    }
    return 0;
}
posted on 2025-08-25 19:06  zhao_ry514114  阅读(3)  评论(0)    收藏  举报