トヨタシステムズプログラミングコンテスト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;
}