洛谷 P3799 Java解法

题目出处点这里

在这里插入图片描述
思路:
四根木棍摆成等边三角形
即a=b=c+d,所有有两根木棍相等,另外两根长度未知
不妨设相等的两根木棍长度都为i,设另外两根其中一根长度为j,设num[i]为长度为i的木棍的个数
得到:i=i=j+(i-j);也就是四根木棍
1、先讨论长度为i相等的两根木棍
就是从num[i]取出两根,即C(num[i],2)
2、再讨论另外长度为j和i-j的两根木棍
①j == i-j 时,可看作从长度为j的木堆里取两个,即C(num[j],2)
②j != i-j 时,可看作分别从长度为j和i-j的木堆里分别取一个,即C(num[j],1)*C(num[i-j],1)
③为避免重复,控制j < i - j;

package violence;

import java.util.Scanner;

public class P2392 {
	
	static Scanner sc;
	static int MO = 1000000007;
	static int n;//n个数
	static int[] num;//存储每个数字出现的个数
	static int max = 0;//存储木棍长度最大值
	static int temp;//临时变量存储sc.nextInt()
	static int sum = 0;
	
	
	public static void main(String[] args) {
		//初始化
		sc = new Scanner(System.in);
		n = sc.nextInt();
		num = new int[5001];
		
		for (int i = 0; i < n; i++) {
			temp = sc.nextInt();
			if (temp > max) {
				max = temp;
			}
			num[temp]++;
		}
		
		/**
		 * 易知:a=b=c+d
		 * 一、即先取两支一样长且长度为i的木棍
		 * 二、再从比i长度小的木棍取两支木棍j、i-j
		 * 	  ①j == i-j,从相同长度木堆取两个
		 * 	  ②j != i-j,从不同长度两个木堆分别取一个
		 * 	  ③为避免取重复,应控制 j < i - j,即j < i / 2
 		 */
		
		//如果从长度为1的木堆开始取两个,很明显没有这种情况,因此从长度为2的木堆开始取
		for (int i = 2; i <= max; i++) {
			if (num[i] >= 2) {//此木堆超过两支木棍
				 int fs = C(num[i], 2) % MO;
				//取完两支长短一样的木棍后,开始取另外两根长度未知的
				for (int j = 1; j <= i / 2; j++) {
					//1、长度一样;那么就在同一木堆取两个
					if (j == i - j && num[j] >= 2) {
						sum = (sum + fs * C(num[j], 2)) % MO;
					}
					//2、长度不一样;那么就在两个不同木堆分别取一个
					if (j != i - j && num[j] >= 1 && num[i-j] >= 1) {
						sum = (sum + fs * C(num[j], 1) * C(num[i-j], 1)) % MO;
					}
				}
			}
		}
		
		System.out.println(sum);
	}

	// 求组合数
	// 要么C(n,1) 要么C(n,2)
	public static int C(int k, int r) {
		if (r == 1) {
			return k % MO;
		}
		return (k * (k - 1) / 2) % MO;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值