HDU2276(矩阵快速幂)

来源:互联网 发布:沙特军事知乎 编辑:程序博客网 时间:2024/06/07 12:39

题目链接:点击打开链接

这道题如果不跟我说是矩阵快速幂的话  我很可能就想不到。还是由别人的提醒  我才做了出来。

题意是给你一串数只有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);
    }
}


原创粉丝点击