计蒜客 蒜头君的兔子
这是一道与之前相比难度略有提升的矩阵题
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;
}
辣鸡老年选手AFO在即