C - Snake Numbers Editorial
by
yuto1115
解説
問題文中では \(10\) 以上の整数についてのみヘビ数が定義されていますが、簡単のため、本解説では \(10\) 未満の正整数も全てヘビ数であると定義することにします。(\(L \geq 10\) のため、\(10\) 未満の整数については好きにヘビ数を定義して問題ありません。)
\(f(R)\) を \(R\) 以下のヘビ数の個数と定義します。求める答えは \(f(R)-f(L-1)\) と表せるので、一般に、与えられた正整数 \(R\) について \(f(R)\) を求められればよいです。 以下その方法を解説します。
まず前提として、\(R\) は最大で \(10^{18}\) になるため、\(R\) 以下の正整数それぞれについて一つずつヘビ数であるか確かめることはできません。 そのため、\(R\) の十進数表記に着目して、より効率的に \(R\) 以下のヘビ数の個数を求める必要があります。
\(R\) が十進数で \(n\) 桁の数であり、上から \(i\ (1\leq i\leq n)\) 桁目の数が \(d_i\) であるとします。このとき、\(R\) 以下の任意の正整数 \(x\) は以下のいずれかちょうど一つの条件を満たします。逆に、以下のいずれかを満たす正整数 \(x\) は全て \(R\) 以下です。
- \(x=R\) である
- \(x\) は \(n\) 桁の数であり、上から \(k\ (1\leq k\leq n-1)\) 桁目までの数が \(R\) と一致し、上から \(k+1\) 桁目の数が \(d_{k+1}\) より小さい
- \(x\) は \(n\) 桁の数であり、上から \(1\) 桁目の数が \(d_1\) より小さい
- \(x\) は \(k\ (1\leq k\leq n-1)\) 桁の数である
上記 1~4 のそれぞれについて、その条件を満たす正整数 \(x\) のうちヘビ数であるものの個数を計算することを考えましょう。すると、以下のようになります:
- \(R\) がヘビ数ならば(すなわち、全ての \(i\ (2\leq i\leq n)\) について \(d_1 > d_i\) を満たすならば)\(1\) 個。そうでないならば \(0\) 個。
- ある \(i\ (2\leq i\leq k)\) について \(d_1 \leq d_i\) ならば \(0\) 個。そうでないならば、\(k+1\) 桁目の数が \(d_1\) 未満かつ \(d_{k+1}\) 未満で、\(k+2\) 桁目以降の数が全て \(d_1\) 未満ならば良いので、\(\min\{d_1, d_{k+1}\}\times d_1^{n-(k+1)}\) 個。
- 上から \(1\) 桁目の数が \(1\) 以上 \(d_1\) 未満で、\(2\) 桁目以降の数がそれより小さければ良いので、\(\displaystyle \sum_{i=1}^{d_1-1} i^{n-1}\) 個。
- 上から \(1\) 桁目の数が \(1\) 以上 \(9\) 以下で、\(2\) 桁目以降の数がそれより小さければ良いので、\(\displaystyle \sum_{i=1}^{9} i^{k-1}\) 個。
以上の数を全て計算して足し合わせれば答えがもとまります。2 と 4 については \(k=1,2,\dots,n-1\) それぞれについて計算する必要があることに注意してください。
なお、下記の実装例においては、1 と 2、3 と 4 をそれぞれまとめて計算しています。
実装例 (C++) :
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll int_pow(ll a, ll t) {
ll res = 1;
for (int i = 0; i < t; i++) res *= a;
return res;
}
ll count(ll r) {
vector<int> digit;
while (r) {
digit.push_back(r % 10);
r /= 10;
}
reverse(digit.begin(), digit.end());
int n = digit.size();
ll res = 0;
for (int i = 1; i <= n; i++) {
if (i == n) {
res++;
break;
}
res += int_pow(digit[0], n - 1 - i) * min(digit[0], digit[i]);
if (digit[i] >= digit[0]) break;
}
for (int i = 0; i < n; i++) {
int mx = (i ? 9 : digit[0] - 1);
for (int j = 1; j <= mx; j++) {
res += int_pow(j, n - 1 - i);
}
}
return res;
}
int main() {
ll l, r;
cin >> l >> r;
cout << count(r) - count(l - 1) << endl;
}
posted:
last update: