Problem:
Score : 700 points

Problem Statement

N problems are proposed for an upcoming contest. Problem i has an initial integer score of A_i points.

M judges are about to vote for problems they like. Each judge will choose exactly V problems, independently from the other judges,
and increase the score of each chosen problem by 1.

After all M judges cast their vote, the problems will be sorted in non-increasing order of score, and the first P problems will be chosen for the problemset.
Problems with the same score can be ordered arbitrarily, this order is decided by the chief judge.

How many problems out of the given N have a chance to be chosen for the problemset?

Constraints

2 \le N \le 10^5

1 \le M \le 10^9

1 \le V \le N - 1

1 \le P \le N - 1

0 \le A_i \le 10^9

Input

Input is given from Standard Input in the following format:

N M V P
A_1 A_2 ... A_N

Output

Print the number of problems that have a chance to be chosen for the problemset.

Sample Input 1

6 1 2 2
2 1 1 3 0 2

Sample Output 1

5

If the only judge votes for problems 2 and 5, the scores will be 2 2 1 3 1 2.
The problemset will consist of problem 4 and one of problems 1, 2, or 6.

If the only judge votes for problems 3 and 4, the scores will be 2 1 2 4 0 2.
The problemset will consist of problem 4 and one of problems 1, 3, or 6.

Thus, problems 1, 2, 3, 4, and 6 have a chance to be chosen for the problemset. On the contrary, there is no way for problem 5 to be chosen.

Sample Input 2

6 1 5 2
2 1 1 3 0 2

Sample Output 2

3

Only problems 1, 4, and 6 have a chance to be chosen.

Sample Input 3

10 4 8 5
7 2 3 6 1 6 5 4 6 5

Sample Output 3

8

Solution in Scala (2.11.7) (judge verdict: Wrong Answer)



object Main {

  // TODO: ....
  def main(args: Array[String]): Unit = {
    val sc = new java.util.Scanner(System.in)

    val N, M, V, P = sc.nextInt()
    val A = Array.fill(N)(sc.nextLong()).sorted

    // 最初のスコアからM人のジャッジがV問のスコアを1ずつあげる
    // その際に問題が大きい順に並べられP問が選ばれる
    // 同スコアの場合は任意に決定されるということは, P+X問実際には選択されうるということ
    // 可能性判定すれば良い
    // 問題によって後から加算されるスコアが変動したりしない
    // まず問題の初期スコアで昇順ソートしておいて
    // c(Ai) := 初期点Aiを持つ問題が問題セットに採用される可能性を持つか？
    // という関数で二分探索すれば良さそう
    // では、そのような判定をどのように行うか？というところである
    // 無難に考えると, 対象の点数が最大まで加算された場合に採用できるか？
    // という制約をさらに加える (= Ai + M, 全員のジャッジがその問題を選んだケース)
    // 自分の点は最大に加算し, それ以外の V - 1問 について小さい順に M点加算させた場合
    // 自分の点がP問内に入るか？という判定である,
    // 実際に全てに加算させる必要はなく
    // 小さい順に並べた時の P min (V - 1) 番目の点数 以上の場合, 採用できる！
    // ↑ 怪しい
    // 既に選択した問題が 最大上昇の M 点加算されるという想定だと,
    // 元々のスコアが Ai より以下のものに対してはどうやっても勝てる（同スコアなら選ばれるので）
    // (N - |Ai以下の数|) >= V の時, Ai以上の数も選んでいく必要がある
    // (V - (N - |Ai以下の数|)) 問だけ, M人のジャッジが選ぶことになる
    // ((Aij + M) < Aij') のような Aij'が存在する場合, そもそも勝てないので, それらの問題は
    // 毎回選択することにする.
    // (実際には (V - (N - |Ai以下の数|)) - (|(Aij + M) < Aij'となるAij'|))問だけ, M人のジャッジが選ぶことになる
    // 各Aij'問題で, どれだけ上げられるか?の許容量は
    // ((Aij + M) - Aij') >= 0の場合, (((Aij + M) - Aij') min M)回だけ選択されても良い
    // もし, この許容量内で収まる場合には問題なく選べる
    // 一回で減らせるのは(((Aij + M) - Aij') min M)までだが,
    // これを ((V - (N - |Ai以下の数|)) * M) 点減らし切れればOK
    // もし減らしきらないうちに ((Aij + M) < Aij') のような Aij'が出てきてしまうと
    // ceil(残りの点 / M)の選択し分だけ勝てないものが出てくるので, それが > P の時NGです
    def solve(N: Int, M: Int, V: Int, P: Long, A: Array[Long]): Int = {
      def check(i: Int): Boolean = {
        val aLowerN: Long = lowerBounds(A(i)) // A(i)以下の問題数
        val aMLowerN: Long = lowerBounds(A(i) + M)
        val fixedProblems: Long = N - aMLowerN // 常に勝てない問題数
        if ((N - i + 1) <= P) return true
        if (fixedProblems >= P) return false // 常に勝てない問題数がP以上ならNG
        def loop(j: Int, acm: Long): Long =
          if (j >= aLowerN) {
            if (N - j <= P - 1) loop(j - 1, acm + M)
            else loop(j - 1, acm + ((A(i) + M - A(j)) min M))
          } else acm
        val OK = aLowerN * M + loop(N - 1, 0)
        OK >= (M * V)
      }
      // lower 以下の A の要素数を返す
      def lowerBounds(lower: Long): Int = {
        def loop(left: Int, right: Int): Int = {
          if (right - left > 1) {
            val mid = left + (right - left) / 2
            if (A(mid) > lower) loop(left, mid)
            else loop(mid, right)
          } else right
        }
        loop(-1, N)
      }
      def lowerBounds2(): Int = {
        def loop(left: Int, right: Int): Int = {
          if (right - left > 1) {
            val mid = left + (right - left) / 2
            if (check(mid)) loop(left, mid)
            else loop(mid, right)
          } else right
        }
        loop(-1, N)
      }
      N - lowerBounds2()
    }

    println(solve(N, M, V, P, A))
  }

}