image.png

BOJ 1206 - 사람의 수

오랜만에 푸는 수학 문제(사칙연산 안해본지 2년지남)라 쉬운건데도 헤맸다.


이 문제가 까다로운 점은 소수점 처리에 있다. 하지만 이는 정수를 이용한 계산으로 변형이 가능하다.

항상 $3$자리수까지 주어지므로 $5.672 \rightarrow 5672$ 처럼 $1000$을 곱해서 다룬다고 생각해보자.

사람이 $1000$명이 있다면 항상 모든 점수를 만들 수 있으므로 사람수는 최대 $1000$명이다. 예를 들어, $3.224$라는 평균 점수는 $3.224 = \dfrac{3224}{1000}$ 이고 $1000$명이 총합 $3224$ 점을 내게 되면 만들어지기 때문이다.

현재 확인하는 사람수가 $i$ 라고 하자. 그럼 사람이 내는 점수에도 $1000$을 곱하므로 $0, 1000, 2000 \cdots 10000i$ 까지의 범위가 총점이 될 것이다.

그럼 이 점수의 집합을 $S$ 라고 하자.

그럼 우린 모든 $n$개의 점수에 대해서 $\text{score}_j = \dfrac{S_x}{i} ~~(1 \le j \le n)$ 임을 만족하는 $x$ 가 $S$ 내에 존재하는지 검사하면 된다.

이는 $O(1000 \cdot N \cdot 10000)$ 정도가 된다.

아래의 코드는 $S$ 내에서 존재하는 $x$ 가 있는지 단순히 모두 검사하는 것이지만 간단한 수식으로 $O(10000)$ 을 뗄 수 있다.

void solve() {  
   int n;  
   cin >> n;  
   vi a;  
   for (int i = 0; i < n; i++) {  
      string s;  
      cin >> s;  
      auto v = spliti<int>(s, ".");  
      a.pb(v[0] * 1000 + v[1]);  
   }  
  
   for (int i = 1; i <= 1000; i++) {  
      // S = {a | 0 ~ i * 10000 까지 1000 단위로}  
      // 이 총점을 k라고 할때, 1 <= j <= n 을 만족하는 모든 정수 j에 대해  
      // a[j] = S_x / i 를 만족하는 x가 존재하는가?  
      int success = 1;  
      for (int j = 0; j < n; j++) {  
         int check = 0;  
         for (int sum = 0; sum <= i * 10000; sum += 1000) {  
            if (a[j] == sum / i) {  
               check = 1;  
               break;  
            }  
         }  
         if (!check) {  
            success = 0;  
            break;  
         }  
      }  
  
      if (success) {  
         cout << i;  
         return;  
      }  
   }  
}

Tags:

Categories:

Updated:

Comments