[模板]矩阵快速幂(以hdu1757为例

来源:互联网 发布:网络优化外泄最低范围 编辑:程序博客网 时间:2024/05/16 17:16
hdu1757 A Simple Math Problem
题意:
题目梗概给出函数式和限制条件
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .
输入k(k<2*10^9)和m(m<10^5),输出f(k)%m的结果
思路:

很明显的矩阵乘法

a0a1a2a3a4a5a6a7a8a9100000000001000000000010000000000100000000001000000000010000000000100000000001000000000010

*

f(x-1)f(x-2)f(x-3)f(x-4)f(x-5)f(x-6)f(x-7)f(x-8)f(x-9)f(x-10)

=

f(x)f(x-1)f(x-2)f(x-3)f(x-4)f(x-5)f(x-6)f(x-7)f(x-8)f(x-9)

所以我们只需求上面(10x10)矩阵的(n-9)次幂,再乘以(10x1)(f(9)~f(0))的矩阵即可

(10x1) = 

9876543210公式 = (10x10)^n*(10x1)

代码:

/**************************************************************    Problem: HDU_1757    User: soundwave    Language: C++    Result: Accepted    Time: 0ms    Memory: 1584KB****************************************************************///#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <stdio.h>#include <vector>using namespace std;typedef vector<int> Vint;typedef vector<Vint> VVint;typedef __int64 LL;int MOD;//矩阵乘法VVint calc(VVint &A, VVint &B){    VVint C(A.size(), Vint(A.size()));    for(int i=0; i<A.size(); i++)    for(int j=0; j<B[0].size(); j++)    for(int k=0; k<B.size(); k++)        C[i][j]  = (C[i][j] + (A[i][k]*B[k][j])%MOD) % MOD;    return C;}//二分快速幂VVint my_pow(VVint A, LL c){    VVint B(A.size(),Vint(A.size()));    for(int i=0; i<A.size(); i++)        B[i][i] = 1;    if(c == 1) return A;    while(c>0){        if(c&1) B = calc(B,A);        A = calc(A,A);        c>>=1;    }    return B;}int main(){    LL k;    while(~scanf("%I64d%d", &k, &MOD)){        VVint A(10,Vint(10));        Vint B(10);        for(int i=0; i<10; i++)            scanf("%d", &B[i]);        if(k < 10) {printf("%I64d\n", k); continue;}        for(int i=0; i<10; i++)            A[0][i] = B[i];        for(int i=1; i<10; i++)            A[i][i-1] = 1;        A = my_pow(A,k-9);        k = 0;        for(int i=0; i<9; i++)            k = (k + (A[0][i]*(9-i))%MOD) % MOD;        printf("%I64d\n", k);    }    return 0;}/*10 99991 1 1 1 1 1 1 1 1 120 5001 0 1 0 1 0 1 0 1 0-------------------45104*/

反思:

最重要的是求出递推关系来,然后转化为矩阵


0 0