队内赛我出的一道题附标程与解题报告

本文探讨了ZZY领养的宠物繁衍规律,通过建立数学模型计算在特定时间点存活的宠物总数,并使用矩阵乘法求解递推数列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ZZY的宠物

Time Limit:1000MS

Description

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隐隐地觉得什么地方怪怪的...所以请将这个数目mod10000

Input

多组数据读到EOF

每组数据一行:

M ( 0<=M<=2000000000 )

最多500组数据

Output

每组输出一行为Case 组号: 答案,即M时刻活着的小宠物个数%10000

SampleInput

0

1

2

3

4

8

SampleOutput

Case 1: 2

Case 2: 2

Case 3: 8

Case 4: 12

Case 5: 32

Case 6: 528

Source

ZZY原创的说..


解题报告:


这道题的灵感来自Fibonacci的那个兔子故事...思想是矩阵乘法解递推数列(应该找不到什么通项公式吧?反正我没试过...)

根据题意建立这样一种数列,数列从0号开始..代表第0个单位时间出生的小宠物...1代表在第1个单位时间出生的小宠物..以此类推..将这个数列某项称作Z[x]

显然..当x>=5时..在第x天活着的小宠物数量sum[x] = z[x-5] + z[x-4] + z[x-3] +z[x-2] +z[x-1] + 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]

显然这个式子是一个递推的公式...那么就可以用矩阵乘法来求解这个递推公式的第x项是多少...观察数列建立关于这个递推数列的"特征“矩阵..

M = 0 1 0 0 0 0

0 0 1 0 0 0

0 0 0 1 00

0 0 0 0 1 0

0 0 0 0 0 1

0 0 1 2 3 0

而初始值为0单位时间的出生情况...可以自己递推出来...为 A = { 0 , 0 , 0 ,0 ,0 ,2 }

要求第x天出生了多少就用z[x] = A*(M^x)...矩阵乘法用递归2分来求解...

要求sum(x)...就分别求出z[x-5] ,z[x-4] ,z[x-3] ,z[x-2] ,z[x-1] ,z[x]再将这几个值加起来就行了....



标程:

#include<iostream> #include<stdio.h> #include<string.h> using namespace std; struct Matrix { int s[6][6]; }h,p,a; int m,T,ans,k; Matrix Mul(Matrix a,Matrix b) { int i,j,k; Matrix h; memset(h.s,0,sizeof(h.s)); for (k=0;k<6;k++) for (i=0;i<6;i++) for (j=0;j<6;j++) h.s[i][j]=(h.s[i][j]+a.s[i][k]*b.s[k][j])%10000; return h; } Matrix Mdata(int n) { Matrix k; if (n==1) return h; k=Mdata(n/2); k=Mul(k,k); if (n%2) k=Mul(k,h); return k; } int main() { T=0; memset(a.s,0,sizeof(a.s)); a.s[5][0]=2; memset(h.s,0,sizeof(h.s)); for (int i=0;i<6;i++) h.s[i][i+1]=1; h.s[5][2]=1; h.s[5][3]=2; h.s[5][4]=3; while (~scanf("%d",&m)) { ans=0; k=6; while (k--) { if (m) p=Mul(Mdata(m),a); else p=a; ans+=p.s[5][0]; if (!m) break; m--; } printf("Case %d: %d\n",++T,ans%10000); } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值