掌握了java,Collections.sort(),第一个参.compare(第二个参) 是按从小到大。
另外,如果需要用到单调队列,java的TreeSet不能满足(因为去重),那么需要每次加入数,都进行重排。实际上单调队列也是如此,只不过b树效率更高。
题意
https://atcoder.jp/contests/abc116/tasks/abc116_d
n个结构体,每个结构体包含x、y两个参数,问:从中选取k个,res = (x的种类)^2 + y的和,求res最大值。
解法
本题运用贪心,先按y从大到小排序,保证优先考虑到的y最大。
假设让res作为最终选中的结果集。那么x种类第一次出现的数,是可以永久保留在res中,因此它的y大,而且占用一个type。第二次出现的数就有可能被替换出去。
c++
#include<bits/stdc++.h>
using namespace std;
struct node
{int x,y;bool operator<(const node&o)const{return y>o.y;}
}a[100005];
int n,k,cot=0;
bool vis[100005];stack<int>s;
int main()
{long long ans=0,res=0,type=0;scanf("%d%d",&n,&k);for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);sort(a+1,a+1+n);for(int i=1;i<=n;i++){if(cot<k){if(!vis[a[i].x]){vis[a[i].x]=true;type++;}else s.push(a[i].y);res+=a[i].y;cot++;ans=max(ans,res+type*type);}else{if(s.empty())break;if(vis[a[i].x]) continue;vis[a[i].x]=true;type++;res+=a[i].y;res-=s.top();s.pop();ans=max(ans,res+type*type);}}cout<<ans<<endl;
}
java (wa了 找不出原因)
import java.util.*;
public class Main {static class Struct{Long x,y;}public static void main(String[] args) {Scanner cin = new Scanner(System.in);int n = cin.nextInt(),k = cin.nextInt();List<Struct> list = new ArrayList<>();for (int i = 0; i < n; i++) {Struct struct = new Struct();struct.x = cin.nextLong();struct.y = cin.nextLong();list.add(struct);}Collections.sort(list, new Comparator<Struct>() {@Overridepublic int compare(Struct o1, Struct o2) {return o2.y.compareTo(o1.y);}});int cnt = 0,type = 0;long ans = 0, res = 0;Stack<Long> stack = new Stack<>();Map<Long, Integer> map = new HashMap<>();for (int i = 0; i <n; i++) {Struct item = list.get(i);if (cnt < k) {if (map.get(item.x) == null) {//第一次出现map.put(item.x, 1);type++;}else{//第i>1次出现stack.push(item.y);}res += item.y ;ans = Math.max(ans, res + type * type);cnt++;}else{// 满了,需要淘汰if (stack.empty()) {break;}if (map.get(item.x) != null) {continue;}// 新加类型,由于排序了那么前面的肯定更加优先map.put(item.x, 1);type++;res = res - stack.peek() + item.y;stack.pop();ans = Math.max(ans, res + type * type);}}System.out.println(ans);}
}