题目链接:点击打开链接
这道题如果不跟我说是矩阵快速幂的话 我很可能就想不到。还是由别人的提醒 我才做了出来。
题意是给你一串数只有0和1。再给你一个m,问你改变m次后,这串数变成什么样子了。变化规则是:看当前数的左边是什么,如果当前数的左边是1,那当前数改变(1变成0,或者0变成1)。如果是0,则不变。这个其实可以这么理解,当前数用bn代表当前数,an代表要bn变化前的数,那么bn=(an+an-1)%2.因为an和an-1只有0和1两种状况,相加对二取余所得结果就是这个规则的变化结果。有了关系式那就好说了,变成矩阵就好了
那么我们举例变化前矩阵为a1,a2,a3,a4。变化后矩阵是b1,b2,b3,b4。要注意的是,b1是看an和a1的。那么关系矩阵就是
1 1 0 0
0 1 1 0
0 0 1 1
1 0 0 1
因为我是喜欢横着写初始矩阵,所以关系矩阵长成这个样子。
还有就是一个小技巧了,当关系矩阵m次幂以后再乘以初始矩阵得到的还是你想要的矩阵,因为矩阵乘法乘一次就是关系式运行一次,关系矩阵m次方再乘以初始矩阵就相当于变化了m次。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int m,len;
char a[1000];
struct matt
{
int mm[105][105];
};
matt operator*(matt a,matt b)
{
matt c;
memset(c.mm,0,sizeof(c.mm));
for(int i=0; i<len; i++)
for(int j=0; j<len; j++)
for(int k=0; k<len; k++)
{
c.mm[i][j]+=a.mm[i][k]*b.mm[k][j];
c.mm[i][j]%=2;
}
return c;
}
void pow(matt s)
{
matt ans,ss;
memset(ans.mm,0,sizeof(ans.mm));
memset(ss.mm,0,sizeof(ss.mm));
for(int i=0; i<len; i++)
ans.mm[i][i]=1;
for(int i=0;i<len;i++)
ss.mm[i][i]=1;
for(int i=0;i<len-1;i++)
ss.mm[i][i+1]=1;
ss.mm[len-1][0]=1;
for(int i=0;i<len;i++)
{
for(int j=0;j<len;j++)
printf("%lld",ss.mm[i][j]);
printf("\n");
}
while(m)
{
if(m&1)
{
ans=ans*ss;
}
ss=ss*ss;
m>>=1;
}
for(int i=0;i<len;i++)
{
for(int j=0;j<len;j++)
printf("%lld",ans.mm[i][j]);
printf("\n");
}
s=s*ans;
printf("%d",s.mm[0][len-1]);
for(int i=0;i<len;i++)
printf("%d",s.mm[0][i]);
printf("\n");
}
int main()
{
while(~scanf("%d",&m))
{
scanf("%s",a);
len=strlen(a);
matt s;
for(int i=0;i<len;i++)
s.mm[0][i]=a[i]-'0';
pow(s);
}
}