这道题目与#288.[2004]合并果子
比较类似,想必思路应该是
for i in [1,n-1) then
sort a+i to a+n
q1 <- a[i]
q2 <- a[i+1]
a[i+1] <- ( q1 + q2 ) /k
其中,n为题目中的n,a为数组,k为题目中的k,q1和q2为两个int类型的临时变量,sort同sort(a+i,a+n,cmp)
(其中cmp将其转换为递减排序)。
很明显,如果一直这样一直sort,复杂度可想而知啊:O(n * n log2 n)至O(n^3)……
但可以水过哦
这里介绍优先队列,即大根堆,不必知道它是如何运作的,每次取top()值时,就可以得到队列中最大的元素!
代码部分(片段)
#include <queue>
#include <vector>//想要用优先队列就要带的东西
-
int n,k,w,a1,a2;//n和k同题目中的n和k;w为临时变量,用于存储w_i;a1和a2存储待处理项,即要“合并”的两个数
priority_queue < int > q;//定义方法
//or
//priority_queue < int , vector < int > , less < int > > q;
就像queue一样,其中的int可以换成其它类,如string,char,double等。
其中的lass参数决定了排序方案,greater决定每次取top()值为队列中最小的值(pop()同理),而lass可以让其返回最大的值。
用这个方案可以减少一定的复杂度:O(n * n log2 n),要更快的会就只能去追求桶排序了。
for(int i=1;i<=n;i++){
scanf("%d",&w);//我下过狠言:从此再也不用cin,cout。(前几天的一次60就是因此)
q.push(w);//与queue同理
}
-
while(q.size()>1){//每次处理两个,所以必须大于一
a1=q.top(),q.pop();
a2=q.top(),q.pop();//取出来
q.push((a1+a2)/k);//模拟
}
看起来还是很简单的,但这样做法有个弊端:由于每次都取两个数,而结果强制去小数,所以合并了[2,2]->(2+2)/2=2和[2,3]->(2+3)/2=2可以说是等价的,但是会浪费一个数2,所以有HACK数据:
4 5
30 31 33 34
其实Luogu上很多人过不去正是因此。应为我们的算法很天真:
30 31 33 34
merge [34,33]
13 30 31
merge [31,30]
12 13
merge [13,12]
5
但实际上……
merge [30,34]
12 31 33
merge [31,33]
12 12
merge [12,12]
4
所以这道题目在Luogu上很有争议的,而如果想试试,可以看看这个:https://www.luogu.com.cn/discuss/464526?page=5 ,可以看出,这有点不实际,所以暂时用这个方法是没有问题的,有待更多研究和结论。