ccf-csp 201312-4 有趣的数(Java)

文章目录

  • 问题描述
  • 格式要求
  • 解题思路
  • AC代码
  • 注意事项

官网传送门

问题描述

我们把一个数称为有趣的,当且仅当:
  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
  3. 最高位数字不为0。
  因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
  请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。

格式要求

输入格式
  输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。
输出格式
  输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。
样例输入
4
样例输出
3

解题思路

  • 首先我们可以知道开头数字肯定是2
  • 对于n位的数字,假定其中包含p个0和1,q个2和3,其中   p , q ≥ 2   \,p,q\ge2\, p,q2
  • 为这p个0和1挑选位置,有   C n − 1 p   \,C_{n-1}^{p}\, Cn1p种情况,因为首位置肯定是2,所以只有n-1个位置供挑选
  • 接下来再确定p中0和1各有几个,0的数目可以为1到p-1,所以共p-1种情况,对于每一种情况直接将0放到选中的p的空位的前面,1放到空位的后面即可
  • 对于q-1个2和3(不算首位的2),2的数目可以为0到q-2,所以共q-1种情况
  • 所以共有   ∑ p = 2 n − 2 ( p − 1 ) ∗ ( n − p − 1 )   \,\sum\limits_{p=2}^{n-2}(p-1)*(n-p-1)\, p=2n2(p1)(np1)种情况,编写代码求该公式即可

AC代码

import java.math.BigInteger;
import java.util.Scanner;

public class Main {

	static final int NUM = 1000000007;
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		in.close();
		System.out.println(getAnswer(n));
	}

	//排列组合法求解
	public static BigInteger getAnswer(int n) {
		BigInteger result = BigInteger.valueOf(0);
		for (int i = 2; i <= n - 2; i++) {
			result = result.add(c(n-1, i).multiply(BigInteger.valueOf((i - 1) * (n - 1 - i))));
		}
		return result.mod(BigInteger.valueOf(NUM));
	}
	
	//组合计算函数
	public static BigInteger c(int n, int k) {
		if (n - k < k)
			k = n - k;
		
		//组合数分子部分,即n*(n-1)*...*(n-k+1)
		BigInteger numerator = BigInteger.valueOf(1);
		//组合数分母部分,即1*2*...*k
		BigInteger denominator = BigInteger.valueOf(1);
		
		for (int i = 0; i < k; i++) {
			numerator = numerator.multiply(BigInteger.valueOf(n-i));
			denominator = denominator.multiply(BigInteger.valueOf(i+1));
		}
		return numerator.divide(denominator);
	}
}

注意事项

  • 观察下面一段组合函数求解代码:
	public static BigInteger c(int n, int k) {
		if (n - k < k)
			k = n - k;
		
		BigInteger result = BigInteger.valueOf(1);
		
		for (int i = 0; i < k; i++) {
			result = result.multiply(BigInteger.valueOf(n-i)).divide(BigInteger.valueOf(i+1));
		}
		return result;
	}

看上去好像没有什么问题,甚至比AC代码中的还要简洁,本人就是在这里卡了好长时间,苦死宝宝了,我还是太菜,一直就没往它身上想。
其中result.multiply(BigInteger.valueOf(n-i)).divide(BigInteger.valueOf(i+1))不一定是整数,所以如果采用上面这种写法的话会有精度损失,而且每一步的损失都叠加在了一起,最后一顿冥思苦想不得其解。

你可能感兴趣的:(Java,Csp)