给了n个灯泡的状态,他们绕成一个环,0是灭,1是亮,每一秒灯泡的状态都会改变,规则是如果当前这个灯泡的左边的灯泡当前是状态1,那么下一秒当前的这个灯泡状态就改变0变1,1变0,最后问你m秒后的状态。
思路:
我们先找当前状态和下一个状态的关系(状态也就是秒),我们可以抽象成这么一种关系,如果第i个灯泡的状态是ai,那么下一秒的第i个灯泡的状态是上一秒的(ai + ai-1)%2,这样关系就出来了,我们构造矩阵,现在就以n=5为例:
上一秒 下一秒
a1 a2 a3 a4 a5 1 1 0 0 0 a1 a2 a3 a4 a5
0 1 1 0 0
* 0 0 1 1 0
0 0 0 1 1
1 0 0 0 1
ok然后就矩阵快速幂了,还有提示下,矩阵是不满足交换律的,也就是说如果把5*5的矩阵放在前面,然后* 初始矩阵=下一个状态,这样构造出来的矩阵会和上面不同,但两个都是对的,最后乘出来的答案一样(只要别吧各自的顺序弄错了)。
#include<stdio.h> #include<string.h> typedef struct { int mat[105][105]; }A; A mat_mat(A a ,A b ,int n) { A c; memset(c.mat ,0 ,sizeof(c.mat)); for(int k = 1 ;k <= n ;k ++) for(int i = 1 ;i <= n ;i ++) if(a.mat[i][k]) for(int j = 1 ;j <= n ;j ++) c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % 2; return c; } A Quick_mat(A a ,int b ,int n) { A c; memset(c.mat ,0 ,sizeof(c.mat)); for(int i = 1 ;i <= n ;i ++) c.mat[i][i] = 1; while(b) { if(b&1) c = mat_mat(c ,a ,n); a = mat_mat(a ,a ,n); b >>= 1; } return c; } int main () { int n ,i ,j ,m; int num[105]; char str[105]; A aa; while(~scanf("%d" ,&m)) { scanf("%s" ,str); n = strlen(str); for(i = 1 ;i <= n ;i ++) num[i] = str[i-1] - '0'; memset(aa.mat ,0 ,sizeof(aa.mat)); aa.mat[1][1] = aa.mat[n][1] = 1; for(i = 2 ;i <= n ;i ++) aa.mat[i-1][i] = aa.mat[i][i] = 1; aa = Quick_mat(aa ,m ,n); for(i = 1 ;i <= n ;i ++) { int now = 0; for(j = 1 ;j <= n ;j ++) now = (now + num[j] * aa.mat[j][i]) % 2; printf("%d" ,now); } puts(""); } return 0; }