Google KickStart 2020H-B "Boring Numbers"

ABC-Eぐらいでありそう

問題リンク:

codingcompetitions.withgoogle.com

問題概要

ある正整数Xが"boring"である、とは次のように定義される:「Xを文字列として見た時、左から数えてi(1-index)桁目の偶奇がiの偶奇と一致する」。L以上R以下の"boring"な数は何通りあるか?(1 <= L < R <= 1e18)

解法

func(X) := 「X以下の"boring"な数の個数」とします。桁DPをすれば良いですが、len := (Xの桁数)として1以上len未満桁の数については、必ずX以下になるので、これらの桁数については、あり得る"boring"な数全部を試せばよく、それは明らかに(5^{桁数})の1からlen-1までの和になります。以下、len桁の数のみ考えます。

dp[dig][num][less] := dig桁目をnumにするとき、この値がX未満になることが確定するか? として、Xの大きい桁から順に決めていけば解くことができます。この手のDP遷移は典型ですね。

次のように実装することができます。

// solution for KickStart2020H-B
// author : lynmisakura
#include<bits/stdc++.h>
using namespace std;

using ll = long long;

int len;
string s;
ll dp[20][20][2];
ll func2(int len){
  ll res = 1;
  for (int i = 0; i < len; i++) {
    res *= 5;
  }
  return res;
}
ll func(ll X){

  memset(dp,0,sizeof(dp));

  s = to_string(X);
  len = int(s.size());

  dp[0][0][0] = 1;
  for (int i = 0; i < len; i++) {
    int x = (s[i] - '0');
    for (int from_dig = 0; from_dig < 10; from_dig++) {
      for (int to_dig = 0; to_dig < 10; to_dig++) {
        if((i + 1 - to_dig) % 2 == 0){
          for (int less = 0; less < 2; less++) {
            if(!less){
              if (to_dig < x) {
                dp[i+1][to_dig][1] += dp[i][from_dig][0];
              } else if(to_dig == x){
                dp[i+1][to_dig][0] += dp[i][from_dig][0];
              }else{
                continue;
              }
            }else{
              dp[i+1][to_dig][1] += dp[i][from_dig][1];
            }
          }
        }
      }
    }
  }

  ll res = 0;
  for (int i = 1; i < len; i++) {
    res += func2(i);
  }
  for (int dig = 0; dig < 10; dig++) {
    for (int less = 0; less < 2; less++) {
      res += dp[len][dig][less];
    }
  }

  return res;

}

/*=====================================================*/

void main2(){
  ll L,R;
  cin >> L >> R;
  cout << func(R) - func(L-1) << '\n';
}
int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  //cout << fixed << setprecision(20);

  int tt;cin >> tt;
  for(int i=1;i<=tt;i++){
    cout << "Case #" << i << ": ";
    main2();
  }
}