思路
由于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;
}