【POJ】3233 Matrix Power Series

【算法】二分+矩阵快速幂

【题意】给定矩阵A和整数k,MOD,求A^0+A^1+A^2+...+A^k。

【题解】

定义题目要求的答案为f(n),即:

$$f_n=\sum_{i=0}^{n}A^i$$

当n为偶数时,可以拆成两半,后一半由前一半集体乘A(n/2)得到,即:

$$f_n=f_{\frac{n}{2}}(A^{\frac{n}{2}}+1)$$

当n为奇数时,直接递推:

$$f_n=f_{n-1}*A^n$$

复杂度O(n^3 log k)。

快速幂的单位矩阵是主对角线(左上到右下)全为1,其余全为0,不用memset就超时了,多用stdio.h。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=40;
int n,MOD,kind;
struct Mat{ll a[maxn][maxn];}A;

Mat ch(Mat a,Mat b){
    Mat tmp;
    memset(tmp.a,0,sizeof(tmp.a));
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                tmp.a[i][j]=(tmp.a[i][j]+a.a[i][k]*b.a[k][j])%MOD;
    return tmp;
}
Mat pow(int k){
    Mat tmp=A,ans;
    memset(ans.a,0,sizeof(ans.a));
    for(int i=1;i<=n;i++)ans.a[i][i]=1;
    //快速幂初值为1(单位矩阵)!!! 
    while(k>0){
        if(k&1)ans=ch(ans,tmp);
        tmp=ch(tmp,tmp);
        k>>=1;
    }
    return ans;
}
Mat plus(Mat a,Mat b){
    Mat tmp;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)tmp.a[i][j]=(a.a[i][j]+b.a[i][j])%MOD;
    return tmp;
}
Mat calc(int k){
    Mat tmp;
    if(k<=1)return A;
    if(k&1){
        tmp=plus(calc(k-1),pow(k));
    }
    else{
        Mat tmps=calc(k/2);
        tmp=plus(tmps,ch(tmps,pow(k/2)));
    }
    return tmp;
}
int main(){
    scanf("%d%d%d",&n,&kind,&MOD);
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%lld",&A.a[i][j]);
    Mat ans=calc(kind);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)printf("%lld ",ans.a[i][j]%MOD);
        printf("\n");
    }
    return 0;
}
View Code

 

还有一道题:HDU1588 Gauss Fibonacci

给定k,b,n,m,求:

$$ans=\sum_{i=0}^{n-1}Fib(k*i+b) \ \ mod \ \ m$$

定义A^i表示Fib(i)的斐波那契矩阵(见Fibonacci,左下角项),那么:

$$sum=A^b \times \sum_{i=0}^{n-1}(A^k)^i \ \ mod \ \ m$$

后面将$A^k$视为整体后,就是本题的套路了。

 
posted @ 2017-08-28 22:00  ONION_CYC  阅读(208)  评论(0编辑  收藏  举报