E :ZZY的宠物
描述
ZZY领养了一对刚刚出生的不知名小宠物..巨萌巨可爱!!...小宠物的生命为5个单位时间并且不会在中间出意外翘辫子(如: 从0出生能活到5但活不到6)..小宠物经过2个单位时间成熟..刚刚成熟的一对小宠物能立即生育6只新的小宠物(如: 从0出生的一对在2时成熟并进行第一次生育)...小宠物是很忠诚的..不会在中途换伴侣..每对小宠物生育一次这一对的生育能力就会降低2个..也就是说一对小宠物在第二次生育时就只能生4个了..小宠物成熟后每个单位时间都会尽力的生育(例: 从0出生的一对..2时间生6个..3时间生4个..4时间生2个...5时间生不出..6时间这一对已经挂了..)..生育出来的新小宠物会继续这个过程..
ZZY想知道从单位时间0开始..经过M个单位时间(时间为M时)将有多少只活着的小宠物(0时刻有2只小宠物)
因为ZZY隐隐地觉得什么地方怪怪的...所以请将这个数目mod 10000
输入
多组数据读到EOF
每组数据一行:
M ( 0<=M<=2000000000 )
最多500组数据
输出
每组输出一行为 Case 组号: 答案,即M时刻活着的小宠物个数%10000
样例输入
0
1
2
3
4
8
样例输出
Case 1: 2
Case 2: 2
Case 3: 8
Case 4: 12
Case 5: 32
Case 6: 528
解题思路:
根据题意,设f(n)为第n天活着的宠物,z(n)为第n天出生的宠物,则f(n)=z(n-5)+z(n-4)+z(n-3)+z(n-2)+z(n-1)+z(n);求z(x)是关键。
如何求z(x),由题意可得z(x)=z(x-2)/2*6+z(x-3)/2*4+z(x-4)/2*2=z(x-2)*3+z(x-3)*2+z(x-4);这显然是一个递推公式,由此可以推出如下:
0 1 2 3 4 5
0: 2 0 0 0 0 0
1: 0 2 0 0 0 0
2: 6 0 2 0 0 0
3: 4 6 0 2 0 0
4:20 4 6 0 2 0
行数i代表第i天,列数j代表第i-j天出生的宠物,矩阵的每一行6个数相加为这一天活着的宠物。观察矩阵可以发现,每一行的后5个数不用计算,只需把上一行的6个数去掉最后一个依次搬下来即可,只需要根据公式z(x)=z(x-2)*3+z(x-3)*2+z(x-4)计算每一行的第一个数。如第四行的第一个数20=6*3+2;如何实现这种关系,由此可以想到矩阵乘法(思维跳跃有木有。。)。矩阵乘法有两个关键矩阵,一个为特征矩阵,一个为初始矩阵,本题的特征矩阵为下面第一个,设为x;初始矩阵为下面第二个,设为y。求第n天活着的宠物即求x^n*y,再把所得矩阵的每一个数相加就行了。。。数据很大,n最大为2000000000,矩阵乘法必须用递归二分来求解。
0 3 2 1 0 0 2
1 0 0 0 0 0 0
0 1 0 0 0 0 0
0 0 1 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 1 0 0
Code:
#include<iostream>
#include<cstring>//必须加,不然会产生编译错误,在main()函数外的memset()处
using namespace std;
struct Matrix
{
int s[6][6];
}fea,ori,aim,temp;
Matrix Mul(Matrix a,Matrix b)
{
Matrix temp1;
int i,j,k;
memset(temp1.s,0,sizeof(temp1.s));
for(i=0;i<6;i++)
for(j=0;j<6;j++)
{
for(k=0;k<6;k++)
temp1.s[i][j]=(temp1.s[i][j]+a.s[i][k]*b.s[k][j])%10000;
}//矩阵相乘用三重for循环
return temp1;
}
int main()
{
memset(fea.s,0,sizeof(fea.s));
fea.s[0][1]=3;fea.s[0][2]=2;fea.s[0][3]=1;
for(int i=1;i<6;i++)
fea.s[i][i-1]=1;
memset(ori.s,0,sizeof(ori.s));
ori.s[0][0]=2;
int n,T=0;
while(cin>>n)
{
memset(aim.s,0,sizeof(aim.s));
for(int j=0;j<6;j++)
aim.s[j][j]=1;
temp=fea;
while(n)
{
if(n%2==0)
{
temp=Mul(temp,temp);
n/=2;
}
else
{
aim=Mul(aim,temp);
n-=1;
}
}
int sum=0;
aim=Mul(aim,ori);
for(int k=0;k<6;k++)
sum+=aim.s[k][0];
cout<<"Case "<<++T<<": "<<sum%10000<<endl;
}
return 0;
}
最后总结矩阵乘法可以解决的问题。(暂无。。)