【JAVA】求数组前K个数中固定位置元素之和Pro20210524
题目
用户用餐后会在外卖应用上对食物的满意度进行评价。(满意度分数始终大于0)
研究满意度的专家称,当把满意度分数按照从小到大的顺序排列时,某个(X/Y)位置的满意度非常重要。因此作为管理满意度的负责人丽雅,她想逐个接收分数后进行处理。
每当接收的满意度为Y的倍数时,会调查X/Y位置的满意度并进行记录。(如果X=3,Y=4的情况,满意度有4个时取第三个分数,有八个时取第六个分数。)
然而,有时候用户也会删除他们的满意度分数。这种情况,为了方便会把该满意度分数接收为负数,然后删除该分数。(确定删除只会发生在已存在的分数上。)然而删除后,数据个数重新变成Y的倍数时,也仍然需要调查满意度分数并进行记录。
让我们思考一下 X=3,Y=4,并且按照 7、5、3、1、-1、7、7、5、6、1、-7、1 的顺序接收12个满意度分数的情况。
首先按照7、5、3、1的顺序输入时,输入的数据个数满足Y的倍数,所以按升序排列时,会成为[图1],X/Y位置的满意度分数是5。
接着输入了-1时,会如上[图2]一样,前面的1会被删除(请注意,负数值本身不是输入值,而是要删除的值), 然后输入7,会成为[图3]。此时,数据个数重新会变成Y的倍数,X/Y位置的满意度值为7。
然后输入7、5、6、1时,数据会成为Y的倍数,会有8个值按从小到大排序,此时跟[图4]一样,这时X/Y位置的值为7。
最后输入-7、1时,跟上述的条件一样,会删除一个跟-7的绝对值相同的7,然后添加1后,数据个数又会变成Y的倍数,成为[图 5]。此时的X/Y位置的值为6,所以符合条件的位置上所在的满意度分数之和为25(5+7+7+6)。
求出丽雅记录的满意度之和。
[限制条件]
1.输入的满意度分数的个数N为介于4到300,000之间的整数。
2.满意度分数为介于-1,000,000,000 到 1,000,000,000 之间的整数,分数为整数时,表示用户输入的满意度,分数为负数时,表示用户删除的满意度。不会给出0。
3.删除时,存在多个相同的满意度绝对值时,只删除其中一个满意度。
4.不会删除不存在的满意度。
5.X和Y是介于1到N的整数,且必须为互质数。
6.X小于Y。
[输入]
首先给出测试用例数量T,接着给出T种测试用例。每个测试用例的第一行给出数据个数N,以及空格区分给出表示比率的X,Y。第二行空格区分给出N个数字。
[输出]
每个测试用例输出一行。各测试用例输出#x(x是测试用例的编号,从1开始),加一个空格,输出丽雅调查的满意度之和。
[输入输出 示例]
(输入)
3
12 3 4
7 5 3 1 -1 7 7 5 6 1 -7 1
6 2 3
3 -3 2 4 4 1
9 2 3
7 2 6 2 7 7 3 3 7
(输出)
#1 25
#2 4
#3 20
方法一:优先级队列
思路:
维护两个优先级队列,一个降序,一个升序;
确保在有效元素的个数P是Y的倍数时,前 (P / Y) * X 个在升序的PQ中,后 P - (P / Y) * X 个在降序的PQ中;
添加数字时,优先往降序的PQ中添加(即:当 P / Y < X 时,往降序的PQ中添加;当 P / Y >= X 时,往升序的PQ中添加);
出现要删除的数D时,确认这个数在哪个PQ中(与降序PQ的有效元素中的最大值M比较,当 D <= M时,D在降序PQ中,反之则在升序PQ中),优先从降序的PQ中删除(不是真删除,需要一个集合,记录某个元素删除的次数);
当效元素的个数P是Y的倍数时,从降序PQ中获取最大有效元素(若获取的最大值,被删除的次数大于0时,重新获取,并将该元素的删除次数减一)累加为SUM;
SUM即为所求。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class Solution {
static HashMap<Integer, Integer> hm;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int T = Integer.parseInt(st.nextToken());
for (int t = 1; t <= T; t++) {
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int X = Integer.parseInt(st.nextToken());
int Y = Integer.parseInt(st.nextToken());
PriorityQueue<Integer> pqL =