【每日蓝桥】61、一八年省赛Java组真题“堆的计数”

你好呀,我是灰小猿,一个超会写bug的程序猿!

欢迎大家关注我的专栏“每日蓝桥”,该专栏的主要作用是和大家分享近几年蓝桥杯省赛及决赛等真题,解析其中存在的算法思想、数据结构等内容,帮助大家学习到更多的知识和技术!

标题:全球变暖

我们知道包含 N 个元素的堆可以看成是一棵包含 N个节点的完全二叉树。

每个节点有一个权值。

对于小根堆来说,父节点的权值一定小于其子节点的权值。

假设 N个节点的权值分别是 1∼N,你能求出一共有多少种不同的小根堆吗?

例如对于 N=4

有如下 3种:

    1

   / \

  2   3

 /

4

 

    1

   / \

  3   2

 /

4

 

    1

   / \

  2   4

 /

3

由于数量可能超过整型范围,你只需要输出结果除以 1000000009的余数。

输入格式

一个整数 N

输出格式

一个整数表示答案。

数据范围

对于 40%的数据,1≤N≤1000;
对于 70% 的数据,1≤N≤10000;
对于 100% 的数据,1≤N≤100000。

输入样例:

4

输出样例:

3

资源约定: .

峰值内存消耗(含虚拟机) < 256M

CPU消耗< 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“ 请您输...”的多余内容.

所有代码放在同-一个源文件中,调试通过后,拷贝提交该源码.

不要使用package语句。不要使用jdk1.7及以上版本的特性。

主类的名字必须是: Main, 否则按无效代码处理.

解题思路

本题在解题时主要用到的思路人是DP动态规划的思想,我们要了解完全二叉树的定义,它是除了最后一层以外,其他每层都是满二叉树,在最后一层的节点是按照左节点优先的进行排列的,我们需要对每一个节点进行判断,每一个节点上可能的情况都是依据它的上一个节点来完成的,所以我们需要判断每一个节点,是否具有左子树、右子树或者无子树的情况进行判断。

答案源码:

package 一八年省赛真题;

import java.util.Scanner;

public class Year2018_Bt10 {

	static final int MOD = 1000000009;
	public static int N;
	static int [] size;
	static long [] jie;
	static long [] ni;
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		N = scanner.nextInt();
		size = new int[N+1];
		jie = new long[N+1];
		ni = new long[N+1];
		initsize();
		initjie();
		System.out.println(dp());

	}
	
	private static long dp() {
		long [] d = new long[N+1];
		for (int i = N; i >= 1; i--) {
			if (2*i+1<=N) {	//既有左子树,又有右子树
				d[i] = c(size[i]-1,size[2*i])*d[2*i] % MOD *d[2*i+1] % MOD;
			}else if (2*i<=N) {//只有左子树
				d[i] = c(size[i]-1,size[2*i])*d[2*i] % MOD;
			}else {//无子树
				d[i] = 1;
			}
			
		}
		return d[1];
	}
	
	private static long c(int n, int r) {
		return jie[n] * ni[r] % MOD * ni[n-r] % MOD;
	}

	private static void initjie() {
		jie[0] = 1;
		ni[0] = 1;
		for (int i = 1; i < N; i++) {
			jie[i] = jie[i-1] * i % MOD;
			ni[i] = pow(jie[i], MOD-2);
			
		}
		
	}
	private static void initsize() {
		for (int i = N; i >= 1; i--) {
			size[i] = (2*i <= N ? size[2*i]:0) + (2*i+1 <= N ? size[2*i+1]:0) + 1;
		}
		
	}
	
	private static long pow(long a,int n) {
		if (a==0) {
			return 0;
		}
		long ans = 1;
		long x = a;
		while (n>0) {
			if ((n & 1) == 1) {
				ans = ans * x % MOD;
			}
			n >>= 1;
			x = x*x%MOD;
		}
		return ans;
	}

}

输出样例:

【每日蓝桥】61、一八年省赛Java组真题“堆的计数”_第1张图片

 

其中有不足或者改进的地方,还希望小伙伴留言提出,一起学习!

感兴趣的小伙伴可以关注专栏!

灰小猿陪你一起进步!

 

你可能感兴趣的:(每日蓝桥,二叉树,数据结构,java,算法,蓝桥杯)