Блог пользователя undefined_error_

Автор undefined_error_, история, 5 лет назад, По-английски

I am trying to solve the problem for a while but couldn't come up an idea. It would be great if someone can help me to solve the problem. Details explanation would be better. Problem Link: https://vjudge.net/problem/LightOJ-1032

Thanks a lot :) sorry for my poor English. :)

  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

»
5 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

use digit dp. the states will be the current digit position, a flag for number already smaller or not, and the previously used digit.

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +5 Проголосовать: не нравится

    Thanks man, can you explain a bit in details. I am not familiar with digit dp. :)

    • »
      »
      »
      5 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится +14 Проголосовать: не нравится

      It's quite hard explaining that problem if you're not familiar with digit dp, so I'm showing a much simpler one first.

      The problem may seem stupid in a sense, it is : given n, find number of positive integers <= n. Ya, very hard. Let's try it with digit dp.

      Say our n = 110. We try to make a number from the most significant decimal place. Initially we assume our number is like *** with no digits determined yet. We say number of ints <= n from this state is dp[2].

      Now we can put 0 or 1 to at the leftmost digit to satisfy <= n condition. We can calculate dp[2] = dp[1] + dp[1].

      But wait, if we put a 0, then next time we can put anything from 0 to 9, but putting 1 means we can only put 0 or 1 at the next time. So we need another state, that is something like "is our number already smaller than n?".

      so initially dp[2][0] means we are at the 2nd place with our number equaling n so far, thus we can't put anything greater than the digit at that place of n. then we can calculate it like dp[2][0] = dp[1][0] (when putting 1) + dp[1][1] (when putting 0) and then,

      $$$dp[1][0] = dp[0][1]$$$ (putting 0) $$$+ dp[0][0]$$$ (putting 1)

      $$$dp[1][1] = dp[0][1]$$$ (putting 0) $$$+ dp[0][1]$$$ (putting 1) $$$+ .... + dp[0][1]$$$ (putting 9)

      It goes like that.

      So $$$dp[i][0/1]$$$ = number of integers $$$<= n$$$ when we are at the ith position (0/1 suggesting already smaller or not)

      $$$dp[i][0] = \sum_{d = 0}^{n_i}dp[i - 1][d < n_i]$$$

      $$$dp[i][1] = \sum_{d = 0}^{9}dp[i - 1][1]$$$

      as for base cases, $$$dp[-1][x] = 1$$$

      This is the essence of digit dp, you only care about what digits you put and how much that contributes to the result.

      Now for that problem, notice you only need to know what you put as previous digit. That way you can add to your contribution when you put two consecutive 1's. It looks like this, $$$dp[i][0/1][prev]$$$ = ans with i digits, with previous digit being prev.

      I'll just show one case,

      $$$dp[i][0/1][1] = dp[i - 1][1][0]$$$ (putting 0) $$$+$$$ (if you can put 1) $$$dp[i - 1][0/1][1]$$$ + (number of integers $$$<= n$$$ from $$$i - 1$$$ th pos :)

      Not so sure if this helped, I'm sure you will also find a lot of other good tutorials online about digit dp, do check those out.

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +5 Проголосовать: не нравится

      Here's a really good blog on Digit-DP