yokobuttonの不定期で競技プログラミングをするブログ

不定期で解けた競技プログラミングコンテストの問題を載せています。

トヨタシステムズプログラミングコンテスト2021(AtCoder Beginner Contest 228) C - Final Day

問題の要約
 N人の生徒が4日間にわたる試験を受けている。
 それぞれの日に行われる試験は300点満点。すなわち,4日間を通した試験の満点は1200点。
 現在3日目までの試験が終わり,これから4日目の試験が行われようとしている。
 i(1<=i<=N)番目の生徒はj(1<=j<=3)日目の試験でPi,j点獲得した。
 それぞれの生徒について,4日目の試験後に上位K位以内に入っていることがあり得るかどうか判定しろ。
 ただし,4日目の試験後の生徒の順位は,その生徒よりも4日間の合計点が高い生徒の人数に1を加えた値とする。
制約
 1<=K<=N<=10^5
 0<=Pi,j<=300(1<=i<=N,1<=j<=3)
入力
 N K
 P1,1 P1,2 P1,3
 .
 .
 .
 PN,1 PN,2 PN,3
考え方
 1,生徒の番号を1ずらす
  1<=i<=N => 0<=i<=N-1
 2,4日目の試験後の順位を聞かれているので,3日目までの試験の点数は合計してよい。
  それぞれの生徒についてPi,1,Pi,2,Pi,3の合計を出す。
 3,4日目の試験後の上位K位以内に入っていることがあり得るかどうかは,生徒iが300点を取りその他の生徒が0点を取ったときの点数でわかる。
  3日目の試験後のK位の点数をcheck_K_score,生徒iの3日目の試験後の合計点数をscore_peoplenum[i]とするとscore_peoplenum[i]+300 >= check_K_scoreならば生徒iは4日目の試験後に上位K位以内に入っていることがあり得る。
 4,check_K_scoreを求める。
  それぞれの生徒の合計を合計点数で割り振る。
  それぞれの合計点数の人数を出す。
  0点から人数を足していく。最終的にN人になるはず。
  0点から合計人数を見ていき,最初にN-合計人数+1がK以下になったところをcheck_K_scoreとする、
 5,それぞれの生徒について,3で求めた条件で判定する。

実際のプログラム
#include<iostream>
#include<vector>

using namespace std;

int main(){
  long long N,K;
  cin >> N >> K;
  vector<long long> score_peoplenum(N);
  for(long long i = 0; i < N; i++){
    long long P1,P2,P3;
    cin >> P1 >> P2 >> P3;
    score_peoplenum[i] = P1 + P2 + P3;
  }
  
  vector<vector<long long>> score(1200+1);
  for(long long i = 0; i < N; i++){
    score[score_peoplenum[i]].push_back(score_peoplenum[i]);
  }
  
  vector<long long> peoplenum(1200+1, 0);
  for(long long i = 0; i <= 1200; i++){
    peoplenum[i] = score[i].size();
  }
  for(long long i = 0; i < 1200; i++){
    peoplenum[i+1] += peoplenum[i];
  }
  long long check_K_score = 0;
  for(long long i = 0; i <= 1200; i++){
    if(N-peoplenum[i]+1 <= K){
      check_K_score = i;
      break;
    }
  }
  
  for(long long i = 0; i < N; i++){
    if(score_peoplenum[i]+300 >= check_K_score){
      cout << "Yes" << endl;
    }else{
      cout << "No" << endl;
    }
  }
  
  return 0;
}