计蒜客 蒜头君的兔子

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

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;
}
posted @ 2018-05-17 13:02  空気力学の詩  阅读(125)  评论(0编辑  收藏  举报