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

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

キーエンスプログラミングコンテスト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;
}