ABC295 F問題 substr = S

atcoder.jp

求めるのは  \sum_{k=L}^{R} f(k) ですが、式のとおりに f(k)を求めてから和の計算をするのは効率が悪いです。
そこで、Sと一致する桁の位置を固定して、それ以外の桁の数を任意とする数のうち、 L 以上  R 以下になるのはいくつかを数えて、
これを桁をずらして和をとることを考えます。
 L 以上  R 以下の範囲の数は、 R 以下および L-1以下の範囲でそれぞれ数えて、その差から求められます。

例として、 R=1234567890123456 以下の数のうち、 S=869120 を含む数を考えます。
 Sと一致する桁の位置を変えて和を計算することになりますが、その中で、678901 の桁の部分が  S と等しくなるケースについて考えてみます。

 R Sより上位の桁は 12345、下位の桁は23456 です。上位の桁が 0~12344 の場合、下位の桁の値にかかわらず Rより小さな値になるため、条件を満たす個数は 12345\times 10^5です。( Sの先頭が0の場合、上位の桁は0~ではなく、1~になるため、その分を減らします。)
上位の桁が Rと同じ12345の数については、それより下位の桁を見る必要があります。( Sの先頭が0の場合、上位の桁が0のケースは除きます。)
 Sと重なる Rの桁の数より Sが小さければ、 Sより下位の桁にかかわらず Rより小さな値になるため、条件を満たす個数に  10^5を追加し、
逆に大きければ、 Sより下位の桁にかかわらず Rより大きな値になるため、条件を満たす個数は 0 です。
等しい場合は、 Sより下位の桁で大小が決まります。0~23456 であればR以下の数になるので、条件を満たす個数に 23456+1を追加します。


コード例 (Julia)

function sum_f(NS, NR, digit_S, digit_R, S0)

  ans = 0

  for digit = 0: digit_R - digit_S    # S より下の桁数

    N1 = 10^digit
    N2 = 10^(digit+digit_S)

    N_low  = mod(NR, N1)              # S より下の桁の数値
    N_cent = div(mod(NR, N2), N1)     # S と重なる桁の数値
    N_up   = div(NR, N2)              # S より上の桁の数値

    if N_up > 0
      if S0
        ans += (N_up - 1) * N1
      else
        ans += N_up * N1
      end
    end

    if S0 && N_up == 0
      continue
    end

    if N_cent > NS
      ans += N1
    elseif N_cent == NS
      ans += N_low + 1
    end
  end

  return(ans)

end  # function solve

function solve()

  # 入力
  readInts() =  parse.(Int,split(readline()))
  readInt()  =  parse(Int,readline())

  T = readInt()

  for t = 1:T

    SS,SL,SR = split(readline())            # 文字列として読み込む

    SL = string(parse(Int,SL) - 1)          # L ==> L-1 に置き換え

    S0 = false                              # S の先頭が 0 かどうか
    if SS[1] == '0'
      S0 = true
    end

    digit_S = length(SS)                    # 桁数
    digit_L = length(SL)
    digit_R = length(SR)

    NS = parse(Int,SS)                      # 整数型へ
    NL = parse(Int,SL)
    NR = parse(Int,SR)

    ans = sum_f(NS, NR, digit_S, digit_R, S0) - sum_f(NS, NL, digit_S, digit_L, S0)

    println(ans)

  end

end

# main
solve()