计蒜客 蒜头君的兔子

这是一道与之前相比难度略有提升的矩阵题

60pts的类斐波那契递推很好写,就是:

  • f[1]=f[2]=1;

  • f[i]=f[i-1]+f[i-2] (3<=i<=11)

  • f[i]=f[i-1]+f[i-2]-f[i-11] (12<=i)

但是这不好用矩阵优化,所以我们换一种思路

首先我们还是采用列向量的形式来表示初始情况,这里我们设一个行的下标为[0..10],列都为[0]的列向量分别表示年龄为0..10岁的兔子各有几只

因此就轻易地得出了[1][0]的位置上是1,其余的都是0(**相当于第1年有1只1岁的兔子)

然后我们想一下,与下一年的转移是什么

首先所有2——9岁的兔子都会生下0岁的兔子,即:

a'[0]=a[2]+a[3]+...+a[10]

所以这个矩阵的第一行就是

0 0 1 1 ... 1

然后所有0——9岁的兔子都会长大1岁,即:

a'[1]=a[0]; a'[2]=a[1]; ... a'[10]=a[9]

然后对应位置上位1即可

最后所有10岁的兔子都会挂掉,即

a[10]=0;(这个就不用管了)

然后我们得到了[0..10][0..10]的递推矩阵

然后还要说吗?矩阵快速幂求之

CODE

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=11,mod=1000000007;
int n;
struct Matrix
{
    int n,m;
    LL a[N][N];
    inline void Fb_init(void)
    {
        n=m=10; register int i;
        memset(a,0,sizeof(a));
        for (i=1;i<n;++i)
        a[0][i]=1;
        for (i=0;i<n-1;++i)
        a[i+1][i]=1;
    }
    inline void cri_init(void)
    {
        n=m=10; register int i;
        memset(a,0,sizeof(a));
        for (i=0;i<=n;++i)
        a[i][i]=1;
    }
    inline void com_init(void)
    {
        memset(a,0,sizeof(a));
        n=10; m=0; a[1][0]=1;
    }
};
inline Matrix mul(Matrix A,Matrix B)
{
    Matrix C; register int i,j,k; 
    C.n=A.n; C.m=B.m; memset(C.a,0,sizeof(C.a));
    for (i=0;i<=C.n;++i)
    for (j=0;j<=C.m;++j)
    for (k=0;k<=A.m;++k)
    C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
    return C;
}
inline Matrix quick_pow(Matrix A,int p)
{
    Matrix T; T.cri_init();
    while (p)
    {
        if (p&1) T=mul(T,A);
        A=mul(A,A); p>>=1;
    }
    return T;
}
int main()
{
    scanf("%d",&n); Matrix F,A;
    F.Fb_init(); A.com_init();
    F=quick_pow(F,n-1);
    A=mul(F,A); LL ans=0;
    for (register int i=0;i<=10;++i)
    ans=(ans+A.a[i][0])%mod;
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjjsb/p/9050498.html