2013年暑假队内选拔赛题解3

来源:互联网 发布:淘宝客服售后面试问题 编辑:程序博客网 时间:2024/05/17 09:42

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;}

最后总结矩阵乘法可以解决的问题。(暂无。。)


原创粉丝点击