闪烁


题目链接:https://www.acwing.com/problem/content/1962/

题解

对于16个灯泡,只有\(2^{16}\)种状态,可以用int存下来。时间t最大是\(10^{15}\),如果全部遍历则会超时。但是每个时间t都是一个状态,而状态数最大只有\(2^{16}\),所以在某个时间一定会有一个出现过的状态,然后形成一个循环节,这时候只需要用剩下的时间对循环节长度取余就能找到,到达最终相同状态所需的时间。

代码

#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int N = 100000;
LL n,a,b;
LL p[N];

int update(int state) {
    int ans = 0;
    for (int i = 0; i < n; i ++ ) {
        int k = (i + 1) % n;
        ans |= ((state >> i & 1) ^ (state >> k & 1)) << i;
    }
    return ans;
}

void print(int state) {
    for (int i = n - 1; i >= 0 ; i -- ) {
        cout << (state >> i & 1) << endl;
    }
}
int main()
{
    int state=0;
    cin >> n >> b;
    for (int i = n-1 ; i >= 0 ; i -- ) {
        cin >> a;
        state |= a << i;
    }
    
    memset(p,-1,sizeof p);
    p[state] = 0;
    
    for (int i = 1; ; i ++ ) {
        state = update(state);
        if(i == b) {
            print(state);
            break;
        }
        else if(p[state] == -1) p[state] = i;
        else {
            int r = ( b - i ) % (i - p[state]);
            while(r -- ) state = update(state);
            print(state);
            break;
        }
    }
    return 0;
}