Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/fontdata.js

AGC018 C : Coins(800)

作成日:2017.07.25
最終更新日:2017.07.25

問題概要

問題本文

 X+Y+Z個の整数の組(Ai,Bi,Ci)がある。各組に対していずれか1つを選ぶ。 但し、A,B,Cを選ぶのはそれぞれX,Y,Z回である。 このとき、選んだ整数の総和の最大値を求めよ。
制約
1X,Y,Z
X+Y+Z105
1Ai,Bi,Ci109

考え方

 問題を線形計画法と見ることができるから最小費用流問題として解きたくなるが、制約が大きいのでダメである。
 とりあえず問題を簡単にするために、制約にはないがZ=0の時を考えてみる。 これは一旦すべての組でBiを選ぶこととして、さらにAiBiのうちX個をとると考えると貪欲法で解ける。
 そこで、元の問題に戻った時になんとかして今考えた問題に帰着することを考える。 A,B,Cの3つのものを2つにするためには、組たちを少なくとも2つに分ける必要がある。 2つに分けるとした時には、対称性より一方はAを、もう一方はBを考えないようにするとして良い。 これを達成するためには、Aを選ばないようにした方でAを選ぶよりも、もう一方からAを選ぶ方が良いことを保証できれば良い。 ここで再びAiBiを考えると、これが小さい組からAを、大きい組からBを選んだ時は選ぶものを逆にすることでより良い結果が得られることがわかる。
 以上より組たちをAiBiでソートした後ある箇所で2つに分割すれば、はじめに考えた問題に帰着できることがわかる。 但し、これを愚直にやると計算量はO(n2)(但しn=X+Y+Z)かかってしまう。 そこで、まずはAを選ばないようにした方だけを組を追加していく順で計算し、次にBを選ばないようにした方だけで同じようにすれば、 priority_queueを用いれば計算量をO(nlogn)に抑えることができる。

ソースコード

マクロ等はこちら

  1. const int MC = 100010;
  2. const LL INF = 1234567890123456;
  3. int X,Y,Z;
  4. int n; //n=X+Y+Z
  5. int A[MC],B[MC],C[MC];
  6. int s[MC]; //A-Bでsortしたときの順
  7. priority_queue<int , vector<int> , greater<int> > QA,QB;
  8. LL mA[MC] , mB[MC]; //QAとmAは22-30行,QBとmBは31-39行参照
  9. LL ans , mx = -INF; //mxは41行参照
  10.  
  11. int main(){
  12. scanf("%d%d%d" , &X , &Y , &Z);
  13. n = X+Y+Z;
  14. repp(i,0,n){
  15. scanf("%d%d%d" , A + i , B + i , C + i);
  16. A[i] -= C[i];
  17. B[i] -= C[i];
  18. ans += C[i];
  19. s[i] = i;
  20. }
  21. sort(s,s+n,[&](const int p , const int q){return A[p]-B[p]>A[q]-B[q];});
  22. repp(i,0,X){
  23. QA.push(A[s[i]]);
  24. mA[X-1] += A[s[i]];
  25. }
  26. repp(i,X,n-Y){
  27. QA.push(A[s[i]]);
  28. mA[i] = mA[i-1] + A[s[i]] - QA.top();
  29. QA.pop();
  30. }
  31. repm(i,n-1,n-Y-1){
  32. QB.push(B[s[i]]);
  33. mB[n-Y] += B[s[i]];
  34. }
  35. repm(i,n-Y-1,X-1){
  36. QB.push(B[s[i]]);
  37. mB[i] = mB[i+1] + B[s[i]] - QB.top();
  38. QB.pop();
  39. }
  40. repp(i,X-1,n-Y){
  41. mx = max(mx , mA[i]+mB[i+1]);
  42. }
  43. printf("%lld\n" , ans + mx);
  44. return 0;
  45. }

解法まとめ

 Ciを引くことになるので、入力の時点で引いている。(16-18行)
 AiBiが大きい順にsortする。(21行)
 priority_queueを用いて[0,i]からAiCiが大きいものをX個選ぶ。(22-30行)
 同様に[i,n1]からBiCiが大きいものをY個選ぶ。(31-39行)
 どこで区切ると良いかを計算する。(40-42行)

AGC018の他の問題 A B D E F

自己紹介

プログラミングとか合成音声とか
詳しくはこちら
twitter

プライバシーポリシー

個人情報利用についてはこちら

最終更新日:2023.03.05

お問い合わせ

このページに関するお問い合わせはこちら

競技プログラミングMENU

問題を解くまでの道のり

その他

全体MENU

寄付モドキ

0冂から10000冂まで
詳しくはこちら