A Simple Math Problem(矩阵快速幂(模板))

【题目来源】:https://vjudge.net/problem/HDU-1757
【题意】
求解数k对应的f(k)%m,关系式如题面所示。
【思路】
既然给出了递推式,又因为k的取值上限相当大,所以使用矩阵快速幂来实现f(k)的求解。这个时候就可以用到系数矩阵来表示题面给出的关系式。
什么是系数矩阵呢?举个例子(从麻省理工学院线性代数视频上看的):
假如有三个未知数:x,y,z;
存在如下关系:(先不管是否有解)
2x+3y=z
x-y=2z
那么用矩阵表示这个关系的话,如下:
A Simple Math Problem(矩阵快速幂(模板))_第1张图片
然而呢,这就是一个系数矩阵表示方程组。。
假设定为1,2,3矩阵。
所以呢,对于这道题,我们可以根据第二个关系式来推导系数矩阵,也就是1矩阵,然后把它用快速幂的思想求出系数矩阵的k-9次方,最后呢,再乘以2矩阵,得到3矩阵。
f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10)
再上面这个式子里可以得到:
f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10)
f(x-1)=1*f(x-1)
f(x-2)=1*f(x-2)
f(x-3)=1*f(x-3)
f(x-4)=1*f(x-4)
f(x-5)=1*f(x-5)
f(x-6)=1*f(x-6)
f(x-7)=1*f(x-7)
f(x-8)=1*f(x-8)
f(x-9)=1*f(x-9)
由此得到系数矩阵(也就是1矩阵):
a0 a1 a2 a3 a4 a5 a6 a7 a8 a9
1_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 1_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_
相对应的2矩阵为:
f(x-1) 0 0 0 0 0 0 0 0 0
f(x-2) 0 0 0 0 0 0 0 0 0
f(x-3) 0 0 0 0 0 0 0 0 0
f(x-4) 0 0 0 0 0 0 0 0 0
f(x-5) 0 0 0 0 0 0 0 0 0
f(x-6) 0 0 0 0 0 0 0 0 0
f(x-7) 0 0 0 0 0 0 0 0 0
f(x-8) 0 0 0 0 0 0 0 0 0
f(x-9) 0 0 0 0 0 0 0 0 0
f(x-10)0 0 0 0 0 0 0 0 0
附:
任何矩阵乘以单位矩阵都等于他本身。下面是5*5的单位矩阵:
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1。
然后,。。。。就没然后了。。。
还有千万要记得。。。定义矩阵*运算时,定义一个矩阵之后,要先清零。。。
【代码】

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int mod=1000000007;
typedef unsigned long long ll;
typedef long long LL;
int k,m;
struct mat
{
    int a[11][11];
}ans,temp,base;
mat operator*(mat s,mat t)
{
    mat r;
    mem(r.a,0);
    for(int i=1; i<=10; i++)
    {
        for(int j=1; j<=10; j++)
        {
            for(int k=1; k<=10; k++)
            {
                r.a[i][j]=r.a[i][j]+s.a[i][k]*t.a[k][j];
                if(r.a[i][j]>=m)
                    r.a[i][j]%=m;
            }
        }
    }
    return r;

}
void print(mat b)
{
    for(int i=1;i<=10;i++)
    {
    for(int j=1;j<=10;j++)
    printf("%4d ",b.a[i][j]);
    printf("\n");
    }
}
void init()
{
    mem(ans.a,0);
    for(int i=1;i<=10;i++)
        ans.a[i][i]=1;
    for(int i=2;i<=10;i++)
        temp.a[i][i-1]=1;
    mem(base.a,0);
    for(int i=1;i<=10;i++)
        base.a[i][1]=10-i;
}
int pow_mat()
{
    init();
    while(k)
    {
        if(k&1)
            ans=ans*temp;
        temp=temp*temp;
        k>>=1;
    }
    ans=ans*base;
    return ans.a[1][1];
}
int main()
{

    while(~scanf("%d%d",&k,&m))
    {
        mem(temp.a,0);
        for(int i=1; i<=10; i++)
            scanf("%d",&temp.a[1][i]);
        if(k<10)
            printf("%d\n",k%m);
        else
        {
            k-=9;
            printf("%d\n",pow_mat());
        }
    }
}

你可能感兴趣的:(ACM竞赛,【数论】--矩阵快速幂,ACM的进程)