• 문제 링크

    https://www.acmicpc.net/problem/14922

  • 사용 언어

    C++

  • 소스

    #include <iostream>
    using namespace std;
      
    int N;
    int A[1000000];
    double Min = 700000000;
    int Index = 0;
      
    int main()
    {
    	cin >> N;
    	for(int i = 0; i < N; i++) cin >> A[i];
    	for(int i = 0; i < N-1; i++) {
    		double Avg = (A[i] + A[i+1])/2;
    		if(Avg < Min){
    			Min = Avg;
    			Index = i;
    		}
    	}
    	for(int i = 0; i < N-2; i++){
    		double Avg = (A[i] + A[i+1] + A[i+2])/3;
    		if(Avg < Min){
    			Min = Avg;
    			Index = i;
    		}
    	}
    	cout << Index;
    }
    
  • 논리

    우선 문제에서 정의한 대로 부분평균 A(i, j)를 정의하겠다.

    문제 해결을 위한 가장 간단한 아이디어는 모든 i, j에 대해 A(i, j)를 계산하고

    그 중 가장 작은 A(i, j)를 찾는 것이다.

    하지만 이 방법의 시간복잡도는 O(N2)이며, 시간초과에러를 만나게 된다.


    몇 개의 예시를 계산해본 결과 다음과 같은 통찰에 달할 수 있었다.

    최소가 되는 부분평균을 찾기 위해서는 연속된 2개 또는 3개의 값만 조사해도 충분하다는 것이다.

    그렇다면 정말 그러한지 증명해보도록 하자.


    • def : \(A\left[i,j\right] = \left\{ a_i, a_{i+1}, ..., a_j \right\}, \quad A(i,j) = \frac{\sum_{k=i}^j a_k}{j-i+1}\)

    • claim : \(\forall A,\ \exists u,v\quad s.t\quad [\; \left|u-v\right|\le2\quad\land\quad\forall i,j\quad A(u,v)\le A(i,j) \; ]\)

    • proof : 수학적 귀납법을 사용하여 증명하도록 하겠다.


      다음은 분명 참이다.

      \[\forall A \quad (|A|=3),\ \exists u,v\quad s.t\quad [\; \left|u-v\right|\le2\quad\land\quad\forall i,j\quad A(u,v)\le A(i,j) \; ]\]


      자, 그럼 아래와 같이 가정하자.

      \[\forall A \quad (|A|=k),\ \exists u,v\quad s.t\quad [\; \left|u-v\right|\le2\quad\land\quad\forall i,j\quad A(u,v)\le A(i,j) \; ]\]


      이 때, 아래 내용이 참이면 임의의 A에 대해 참임이 증명된다.

      \[\forall A \quad (|A|=k+1),\ \exists u,v\quad s.t\quad [\; \left|u-v\right|\le2\quad\land\quad\forall i,j\quad A(u,v)\le A(i,j) \; ]\]


      결론부터 말하면, A의 최소부분평균이 되는 부분배열 m은

      \(A[1,k]\) 또는 \(A[2, k+1]\)에 속해 있다는 것이다.


      특히, \(k=|A[1,k]|=|A[2,k+1]|\) 이므로, m의 길이는 3이하이다.


      일단, 다음은 분명 참이다.

      \[|A|=N \quad \Rightarrow \quad A(1, N) \ge \mbox{min}(A(1,N-2),\;A(N-1,N),\;A(1,2),\;A(3, N))\]


      왜냐하면 아래와 같이 설명할 수 있다.

      \[\begin{cases} A=\{a_1, a_2, ..., a_N \},\\ \\A(1,N)=m,\\ \\a_i=m+b_i \end{cases}\]

      그러면

      \[b_1 + b_2 + ... + b_N = 0\]

      이다.


      그러면

      \[\begin{cases} A(1, N-1) = m + \frac{b_1 + b_2 + ... + b_{N-2}}{N-2} = m - \frac{b_{N-1} + b_N}{N-2}\\ \\ A(N-1, N) = m + \frac{b_{N-1} + b_{N}}{2} \end{cases}\]

      이므로

      \[\begin{cases} A(1, N-2) > m \quad \Rightarrow \quad A(N-1, N) < m \\ \\ A(N-1, N) > m \quad \Rightarrow \quad A(1, N-2) < m \end{cases}\]

      임을 알 수 있다.


      마찬가지로

      \[\begin{cases} A(1, 2) > m \quad \Rightarrow \quad A(3, N) < m \\ \\ A(3, N) > m \quad \Rightarrow \quad A(1, 2) < m \end{cases}\]

      이다.


      또한

      \[\begin{cases} A[1,N-2] \subset A[1,N-1] \\ \\ A[N-1,N] \subset A[2,N] \\ \\ A[1,2] \subset A[1,N-1] \\ \\ A[3,N] \subset A[2,N] \end{cases}\]

      이므로, A의 최소가 되는 부분배열은 \(A[1,N-1], \; A[2,N]\) 에서만 찾으면 되는 것이다.


      이로써 증명이 완료 됐지만, 의문이 남을 수도 있다.

      사실 부분배열의 길이가 2인 것에 대해서만 찾아도 되는 것 아닐까?

      즉, claim을 아래와 같이 선언해도 되지 않을까?

      \[\forall A,\ \exists u,v\quad s.t\quad [\; \left|u-v\right|\le1\quad\land\quad\forall i,j\quad A(u,v)\le A(i,j) \; ]\]

      이 부분은 금세 반례를 들어 부정할 수 있다.

      A = {1, 100, 2} 인 경우를 살펴보자.

      금세 답이 나올 것이다.