HDOJ1205 吃糖果

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1205
  方法1:
如果最大堆-次大堆<=1,那么问题肯定有解:
我们可以从最大和次大里面每次拿一个,然后等他们和第三大堆相等的时候。
每次从三堆里面各拿一个,等他们和第四大堆相等的时候。
每次从四堆里面各拿一个,这样一直拿完所有堆。
问题变成了能不能使得最大堆-次大堆<=1,所以之前我们会从次大堆之外的那些堆里面取。
来让最大堆减少,如果能减到:最大堆-次大堆<=1,那么原问题有解。
能否减到要看:
sum - max - max2 >= max - max2 - 1
是否成立,其中sum为总和,max为最大堆,max2为次大。
整理得:
2 * max - sum <= 1
方法2:
鸽巢原理

1.把某种糖果看做隔板,如果某种糖果有n个,那么就有n+1块区域,至少需要n-1块其他种糖果才能使得所有隔板不挨在一块..也就是说能吃完这种糖果.至少需要其他种类糖果n-1块..(鸽巢原理)

2.数量最多的糖果(隔板)可以构造最多的空间,如果这种糖果有maxn个....那么需要maxn-1个其他种糖果.对于某种数量少于maxn的糖果来说,可以在原本数量最多的糖果构造的隔板上"加厚"原有的隔板...,那么这"某种糖果"就销声匿迹了.....

考虑极端情况.如果某种糖果无法在这maxn+1的空间内构造出符合条件的序列,那么这种糖果至少要有maxn+1+1个(考虑只有两种糖果的情况)...(鸽巢原理)...但是这与数量最多的那种糖果只有maxn个矛盾.....(maxn+1+1>maxn 这不等式不难理解吧....).

证明来自: http://blog.csdn.net/hnust_xiehonghao/article/details/8005832
刚开始也是想到第一种方法,但是没考虑的周全,结果WA了。
后来才找到第二种方法,也WA了,原因是总和sum大于int 的最大值,需要使用Long。
其实两种方法的过程都是一样的,只是思想不同。
另外,题目总写明了使用scanf,对应java,就应该使用streamTokenizer了
下面代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

//至少需要max-1个其他糖果(其他糖果是sum-max个)
public class Main{
	public static void main(String[] args) throws IOException {
		StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		in.nextToken();
		int cases = (int) in.nval;
		while (cases-- > 0) {
			in.nextToken();
			int n = (int) in.nval;
			int max = 0;// 最大数
			long sum = 0;// 糖果总数(一定要使用long!!!!!!!)
			for (int i = 0; i < n; i++) {
				in.nextToken();
				int t = (int) in.nval;
				sum += t;
				if (max < t) {
					max = t;
				}
			}
//			if (sum - max >= max - 1) {//也OK(隔板)
			if (2*max-sum<=1) {//sum-max-max2>=max-max2-1(max2为次大)
				out.println("Yes");
				out.flush();
			} else {
				out.println("No");
				out.flush();
			}
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值