题目描述
现在已知N件商品,和搬运它们其中每一件的费用。现在搬家公司老板Mr.sb决定让我们每次任意选取2件商品。然后这2件商品只算一件商品的费用。但是这个商品的搬运费用是将选出的2个商品的费用之和除以k的运算结果。如此反复。直到只收一件商品的钱。这个就是商店要付的费用。掌柜的想尽可能的少付钱,以便将更多的钱捐给希望工程。所以请你帮他计算一下最少只用付多少钱。
【输入格式】trans.in
【输出格式】
【样例输入】trans.out
【样例输出】
1
输入输出格式
输入格式:
n,k w1,w2.....wn(每一件物品搬运费)
输出格式:
一个数 最少付多少钱
输入输出样例
输入样例#1: 复制
5 2 1 2 3 4 5
输出样例#1: 复制
1
说明
【数据规模】
n、k、wi均为非负数
n和k<=10000
解题思路:
这题的描述看的我想骂街,表达非常不清楚。。。题意是给你一堆数字,每次你能选出两个,把他们相加除以 k ,再放回去,,最后剩下一个时候,剩下的这个值最小是多少……
看懂题之后想到的就是贪心了,因为 k 是固定的,不妨假设是 2 。
那么题就变成了,拿出两数相加除2再放回去,最后成一个时,值最小是多少。肯定是最小的数先加小啊,
举个例子吧【1,3,4,8,9】,先看看每次选最小的【((1+3)/2)=2,4,8,9】,再选最小的两个【((2+4)/2)=3,8,9】,不难看出,1+3除了两次 2 。有点像二分法的感觉,每次都取小的数,总体就向小数方向移动,,要是取大的数,那整体就向大数移动了。
所以用一个优先级队列,每次取两个小的数,计算后再放回,直到剩余一个。
反思错误:
①一开始想取大的数,认为先用大的数,那么被除的次数越多结果就越小了,结果发现整体是向大数移动的。
Java代码(用的模板,所以看着多,实际代码很少):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
// long sta = System.nanoTime();
InputStream is = System.in;
OutputStream os = System.out;
IN cin = new IN(is);
PrintWriter cout = new PrintWriter(os);
SO so = new SO();
so.solution(cin, cout);
// long end = System.nanoTime();
// cout.println("耗时:" + (double)(end-sta)/1e6 + "ms");
cout.close();
}
static final int MOD = (int)1e9 + 7;
//实际代码开始的类--------------------------------------------------
static class SO {
void solution(IN cin, PrintWriter cout) {
int n = cin.nextInt(), k = cin.nextInt();
Queue<Integer> pq = new PriorityQueue<Integer>((a1,a2)->a2-a1);
for(int i=0;i<n;++i) {
pq.add(cin.nextInt());
}
int cur = 0;
while(n>1) {
int a = pq.remove(), b = pq.remove();
cur = (a+b)/k;
pq.add(cur);
--n;
}
cout.println(pq.remove());
}//end solution
}//end SO
//以下是快读部分
static class IN {
private BufferedReader reader;
private StringTokenizer tokenizer;
IN(InputStream is) {
reader = new BufferedReader(new InputStreamReader(is), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
}
}
测试结果: