POJ3070 + HDU1005 + HDU1575 矩阵快速幂入门

这三道算是矩阵快速幂的入门题了。。

1.POJ3070 Fibonacci sequence

先贴大佬博客:https://blog.csdn.net/ccf15068475758/article/details/52846726

初始化:n=1时,F0=0,F1=1,F2=1。可以发现和A矩阵相同,合并为A^n

又因为要输出最后四位数,MOD=10000

附上AC代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define ll long long

const int MOD=10000;
ll n;
typedef struct
{
    ll a[2][2];
}mat;
mat c,res;

mat mul(mat x,mat y,int n)
{
    mat cnt;
    memset(cnt.a,0,sizeof(cnt.a));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            for(int k=0;k<n;k++)
                cnt.a[i][j]+=x.a[i][k]*y.a[k][j]%MOD;
    return cnt;
}
void pow()
{
    c.a[0][0]=c.a[0][1]=c.a[1][0]=1;
    c.a[1][1]=0;
    memset(res.a,0,sizeof(res.a));
    res.a[0][0]=res.a[1][1]=1;
    n--;
    while(n>0)
    {
        if(n&1)
            res=mul(res,c,2);
        c=mul(c,c,2);
        n=(n>>1);
    }
}
int main()
{
    while(cin>>n)
    {
        if(n==-1)
            break;
        else if(n==0)
            cout<<"0"<<endl;
        else
        {
            pow();
            cout<<res.a[0][0]%MOD<<endl;
        }
    }
    return 0;
}

2.HDU1005 Number Sequence

同样先附上博客:https://blog.csdn.net/oranges_c/article/details/55224528

其实递推式不一定全是2*2的矩阵,可以2*1=[2*2]*[2*1]这种的,主要是中间的A^n用到矩阵快速幂,A为方阵。剩下的利用矩阵知识求解就行,比如F(n)=A^(n-2)的第一行*初始化第一列%MOD。

附上AC代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define ll long long
#define pi acos(-1.0)

const int MOD=7;
ll  a,b,n;
typedef struct
{
    ll a[2][2];
}mat;
mat c,res;

mat mul(mat x,mat y,int n)
{
    mat cnt;
    memset(cnt.a,0,sizeof(cnt.a));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            for(int k=0;k<n;k++)
                cnt.a[i][j]+=x.a[i][k]*y.a[k][j]%MOD;
    return cnt;
}
void pow()
{
    c.a[0][0]=a;
    c.a[0][1]=b;
    c.a[1][0]=1;
    c.a[1][1]=0;
    memset(res.a,0,sizeof(res.a));
    res.a[0][0]=res.a[1][1]=1;
    n-=2;
    while(n>0)
    {
        if(n&1)
            res=mul(res,c,2);
        c=mul(c,c,2);
        n=(n>>1);
    }
}
int main()
{
    while(cin>>a>>b>>n)
    {
        if(a==0&&b==0&&n==0)
            break;
        pow();
        cout<<(res.a[0][0]+res.a[0][1])%MOD<<endl;
    }
    return 0;
}

3.HDU1575 Tr A 

这道题也没什么特别的,就是矩阵大小变了,注意mul中n指矩阵大小,要更新。

附上AC代码:(直接作为板子了2333)

//n指矩阵大小,即a的行/列数;k指幂次
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define ll long long
#define pi acos(-1.0)

const int MOD=9973;//注意随题意变化
ll n,k;
typedef struct
{
    ll a[12][12];
}mat;
mat c,res;

mat mul(mat x,mat y,int n)//注意x,y的顺序!一般AB≠BA!!
{
    mat cnt;
    memset(cnt.a,0,sizeof(cnt.a));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            for(int k=0;k<n;k++)
                cnt.a[i][j]+=x.a[i][k]*y.a[k][j]%MOD;
    return cnt;
}
void pow()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            scanf("%d",&c.a[i][j]);
    //res通常初始化为单位矩阵
    memset(res.a,0,sizeof(res.a));
    for(int i=0;i<n;i++)//注意此处循环不能少!
        res.a[i][i]=1;
    while(k>0)
    {
        if(k&1)
            res=mul(res,c,n);
        c=mul(c,c,n);
        k=(k>>1);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        pow();
        ll ans=0;
        for(int i=0;i<n;i++)//求迹
            ans+=res.a[i][i]%MOD;
        cout<<ans%MOD<<endl;
    }
    return 0;
}

 

点赞