【poj3233】Matrix Power Series(递推+矩阵快速幂)

题目描述

传送门

题解

用朴素的矩阵快速幂的话时间无法承受。其实这道题的思路挺奇特的,不是自己想出来的很不爽。
这里有一个递推的思路:考虑k能不能从之前的状态转移过来。答案是肯定的。
k%2==0 时:

sum(k)=i=1kAk=(1+Ak2)(A+A2++Ak2)

k%2!=0
sum(k)=i=1kAk=A+(A+Ak2)(A+A2++Ak2)

也就是说先计算出 sum(k2) 的值就可以经过很少的计算得出 sum(k) 的值,那么我们可以不断递归下去。
有必要说明一点:第一个公式出现了1,它其实就代表了一个单位矩阵,即
I=1000010000100001

满足 AI=IA=A A 为任意矩阵)

代码

#include
#include
#include
using namespace std;

struct hp{
    int a[35][35];
}A,unit;
int n,k,m;

inline hp jia(hp a,hp b){
    hp c;
    for (int i=1;i<=n;++i)
      for (int j=1;j<=n;++j)
        c.a[i][j]=(a.a[i][j]+b.a[i][j])%m;
    return c;
}

inline hp cheng(hp a,hp b){
    hp c;
    memset(c.a,0,sizeof(c.a));
    for (int i=1;i<=n;++i)
      for (int j=1;j<=n;++j)
        for (int k=1;k<=n;++k)
          c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%m)%m;
    return c;
}

inline hp fast_pow(hp a,int p){
    hp ans=unit;
    for (;p;p>>=1,a=cheng(a,a))
      if (p&1)
        ans=cheng(ans,a);
    return ans;
}

inline hp doit(int k){
    if (k==1) return A;
    hp now=doit(k/2);
    if (k%2==0){
        hp x=fast_pow(A,k/2);
        x=jia(unit,x);
        x=cheng(x,now);
        return x;
    }
    else{
        hp x=fast_pow(A,k/2+1);
        x=jia(A,x);
        x=cheng(x,now);
        x=jia(A,x);
        return x;
    }
}

int main(){
    scanf("%d%d%d",&n,&k,&m);
    for (int i=1;i<=n;++i)
      for (int j=1;j<=n;++j)
        scanf("%d",&A.a[i][j]);
    for (int i=1;i<=n;++i)
      unit.a[i][i]=1;
    hp ans=doit(k);
    for (int i=1;i<=n;++i)
      for (int j=1;j<=n;++j)
        printf("%d%c",ans.a[i][j]," \n"[j==n]);
}

你可能感兴趣的:(题解,dp,矩阵)