WUSTOJ 1283: Hamster(Java)

1283: Hamster

参考博客

wust_tanyao的博客

题目

  第0个月有1对仓鼠。仓鼠的寿命是M个月,仓鼠成年后每个月生一对仓鼠(一雌一雄),问N个月后有仓鼠多少对。更多内容点此链接

题目分析

  阅读之前先看看两组数据,如果能推出结果,可以跳过题目分析部分。
  输入:

3 4
5 2

  输出:

3
4

  OK,如果你推算不出来,可以参考下面这个表的推算过程:
  代码中只用了第一个参数(birth[])和第三个参数(adult)。其他参数可直接算出来。递推语句是:

birth[i]等于第i-1个月的adult
i个月的成年数量adult等于第i-1个月的成年数量和出生数量之和减去M+1个月之前的那个月的出生数量(i<M+1就不用减)。
最后结果是第i个月的成年数量加出生数量。
—————————————————————————————————————————
第二条中的减去的那部分,其实是这个月死去的仓鼠数量。因为那一个月出生的仓鼠刚好在这个月死亡。

  如果我说的不是很清楚的话,可以自己对照表格自己慢慢推敲,多思考,多思考,多思考。不要放弃,真滴不难。

  每次碰到这类题,我都要想半天,理不清楚思路QAQ……下面欣赏代码吧&_&

代码

/**
 * time 447ms
 * @author PengHao
 * @version A3.2
 * @date 2019-04-26 上午10:23:03
 */

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(new BufferedInputStream(System.in));
		long[] birth = new long[10001]; // 每个月出生的仓鼠(对)
		int mod = 1000000007; // 取余运算的模
		int N, M; // N个月后存活多少对仓鼠,仓鼠的寿命为M个月
		int M1; // M1=M+1,循环里面要用到,提前算出来节约时间
		birth[0] = 1; // 第0个月买了一对刚“出生”的仓鼠,所以为1
		long adult; // 某个月成年的仓鼠数量(对)
		while (sc.hasNext()) {
			N = sc.nextInt();
			M = sc.nextInt();
			M1 = M + 1;
			adult = 0; // 第0个月成年仓鼠为0对
			// 循环体内计算过i个月后的出生仓鼠数量birth[i]和成年仓鼠数量adult
			for (int i = 1; i <= N; i++) {
				// 上个月成年仓鼠数量(成年后每个月生一对),就是这个月出生仓鼠数量
				birth[i] = adult;
				// 这个月成年仓鼠数量是上个月成年仓鼠数量和上个月出生仓鼠数量之和
				// 减去上个月死亡的仓鼠数量(死的是M+1个月前的那个月出生的仓鼠)
				// 如果没有死的就不用减
				adult += birth[i - 1];
				if (i > M) {
					adult -= birth[i - M1];
				}
				// 前面死的仓鼠数量(birth[i-M1])可能比后面出生的仓鼠(birth[i-1])
				// 多很多,if语句里面就有可能减成负的。
				adult = (adult + mod) % mod; // 因此需要取余
			}
			// 这个月成年数量加出生数量就是这个月存活数量。
			// 这里的成年数量是已经减去了这个月死亡数量的(if语句的作用)。
			System.out.println((adult + birth[N]) % mod); // 可能过大,要取余
		}
		sc.close();
	}

}
代码补充

  思路理清楚了,代码其实不难。需要注意的地方是:1、哪些地方取余,参考博客的代码中取余有重复的,我将它删除掉了;2、int型不够,要用long型;3、参考博客的数组的第0个值我拿到了最外面,减少重复计算;4、将“指针”结构(head,tail)去掉,直接用i操作,减少运算缩短时间;5、循环中要用到M+1,拿到for循环外面定义为M1,减少重复计算。
  这算是斐波拉契的一种变形吧,以前做的那种你可以看成寿命是无穷的,现在只不过多了限制条件而已,减掉那些死亡的就可以了。
  这类找规律的题(从表格就可以看出来),一般都是可以预处理的,但是这道题目预处理的代价太大(内存开销有好几百MB),申请内存时候就挂了。所以我就没用预处理。如果大家想到了优化的预处理方法,欢迎告知本人,谢谢。


写在最后:

  1. 如需转载,请于首页至少注明链接形式的wowpH的博客这几个字;
  2. 代码原创,如需公开引用,不能删除首行注释(作者,版本号,时间等信息)。
  3. 如果有疑问欢迎评论留言,尽量解答。

原文地址:https://www.cnblogs.com/wowpH/p/11060808.html