キーエンスプログラミングコンテスト2021-Nov. (AtCoder Beginner Contest 227) B - KEYENCE building
問題の要約
1からNの番号のついたN人の人がいる。
人iはビルの面積をSiと予想。
本来のビルの面積は4ab+3a+3bである(a,bは正の整数)。
N人のうち、予想した面積が確実に誤りであるとわかる人数を求めよ。
制約
1<=N<=20
1<=Si<=1000
入力
N
S1,...,SN
考え方
1,まず人の番号を1ずつずらす。
1,2,...,N => 0,1,...,N-1
2,人数だけを求めればよいので、番号はついていないのと同じ。よって、Siをソートしてもよい。ソートした数列をSとする。
3,a=1のときbは,4ab+3a+3b=4b+3+3b=3+7b。これが制約から1000以下なので
3+7b<=1000
7b<=997
b<=142
4ab+3a+3bはa,bの対称式なので、a<=142である。
4,1<=a<=142,1<=b<=142のすべての数に対して4ab+3a+3bを計算して、ソートして、重複を削除する。この数列をStureとする。
5,StrueとSの先頭から順にみて、
Strueの要素とSの要素が同じならcountを1増やし、Sの次の要素に移る。
Strueの要素がSの要素より大きい時は、Sの次の要素に移る。
Strueの要素がSの要素より小さい時は、Strueの次の要素に移る。
これをSの全要素が終わるまで繰り返す。
6,Nからcount分を引いた数が予想が誤りである人の数。
実際のプログラム
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int N;
cin >> N;
vector<int> S(N,0);
for(int i = 0; i < N; i++){
cin >> S[i];
}
sort(S.begin(), S.end());
vector<int> Strue;
for(int a = 1; a <= 142; a++){
for(int b = 1; b <= 142; b++){
Strue.push_back(4*a*b+3*a+3*b);
}
}
sort(Strue.begin(), Strue.end());
Strue.erase(unique(Strue.begin(), Strue.end()), Strue.end());
int count = 0;
for(int i = 0, j = 0; i < S.size(); ){
if(Strue[j] == S[i]){
count++;
i++;
}else if(Strue[j] > S[i]){
i++;
}else if(Strue[j] < S[i]){
j++;
}
}
cout << N-count << endl;
return 0;
}