解法
以下 0-indexed であるとする。
まず であるとして、
または
の場合のみ考えれば良い。
(そうでない場合は答えは
である。)
桁の正の整数と
桁の正の整数の和は
桁か
桁になるため、以下では
桁のものを数える。
もし の場合、
桁の正の整数は
個あるため、上で求めた場合の数を
から引けば良い。
を固定したときに、
の桁数が変化しないような正の整数の個数を考える。自分は以下のように書きながら考えた。
A = {1, 1, 1} X[0] X[1] 1 9 - 1 2 9 - 2 3 9 - 3 .............. 8 9 - 8 A = {2, 2, 2} X[0] X[1] 10 90 - 10 11 90 - 11 12 90 - 12 13 90 - 13 .............. 89 90 - 89 A = {2, 3, 3} X[0] X[1] 10 900 - 10 11 900 - 11 12 900 - 12 13 900 - 13 .............. 89 900 - 89 90 900 - 90 .............. 99 900 - 99
こんな感じで考えていくと、 の場合だけ
が大きいと対応する
が存在しなくなってしまうことがわかるため、場合分けをする。
部分と
の部分で分けて計算すると、以下のようになる。
のとき
のとき
あとはこれを実装すれば良い。
#include "my_template.hpp" #include "math/static_modint.hpp" using mint = mint998; using namespace std; void solve() { VEC(i64, A, 3); if (A[0] > A[1]) swap(A[0], A[1]); // A[0] <= A[1] if (!(A[1] == A[2] or A[2] == A[1] + 1)) { print(0); return; } mint c0 = mint(9) * (mint(10).pow(A[0] - 1)); mint c1 = mint(9) * (mint(10).pow(A[1] - 1)); { // A[2] = A[1] となるものを数え上げる mint ans = 0; auto f = [](mint n) -> mint { return n * (n + 1) / 2; }; if (A[0] == A[1]) { // A[0] == A[1] ans += c1 * (mint(8) * mint(10).pow(A[0] - 1)); ans -= f(mint(9) * mint(10).pow(A[0] - 1) - 1); ans += f(mint(10).pow(A[0] - 1) - 1); } else { assert(A[0] < A[1]); ans += c0 * c1; ans -= f(mint(10).pow(A[0]) - 1); ans += f(mint(10).pow(A[0] - 1) - 1); } if (A[2] == A[1] + 1) { ans = c0 * c1 - ans; } print(ans); } /* { // 実験コード vector<i64> lb(3), ub(3); REP(i, 3) { lb[i] = TEN(A[i] - 1); ub[i] = TEN(A[i]) - 1; } int ans = 0; REP(x0, lb[0], ub[0] + 1) { REP(x1, lb[1], ub[1] + 1) { i64 x2 = x1 + x0; if (LEN(to_string(x2)) == A[2]) { // show(make_tuple(x0, x1, x2)); ans++; } } } print(ans); } */ return; } int main() { INT(T); REP(T) solve(); return 0; }
公式解説では 2 次元平面に条件を図示して領域内の格子点の数を求めるとみなしていた。
結局やっていることは変わらないが、見通しが良くなるかもしれない。
余談
実は典型テクがあるらしい。
長方形を斜めに切ったときの面積をもとめる典型テク (x 座標の範囲の制約, y 座標の範囲の制約 を包除) pic.twitter.com/6uyetK2glT
— tatyam (@tatyam_prime) 2023年3月29日
長方形の面積は
かつ
かつ
を満たす領域の面積と考えることができる。
これに対し、制約に関する包除原理をすると上のツイートのような図が出てくる。
例えば上記制約なら
かつ
かつ
かつ
かつ
かつ
かつ
かつ
かつ
の4つの制約を満たす領域を足し引きすることで求めることができるという意味である。
そしてこれらの制約を満たす領域は点と直線の位置関係を考えれば比較的簡単に求めることができる。(なお、一部は面積が になってしまうため、元のツイートの第4項が出てくるのも理解できる。)
一見回りくどいようなことをしているように見えるが、以下のような場合でも成立しており、細かい場合分けが不要になるという利点がわかると思う。
なお、公式解説2はこれらの制約に加え、直線に関する制約も包除原理したものだと考えることができそうである。(多分)
感想
コンテスト中に解けたがやや遅かった。 包除原理が勉強になった。
メモ:AOJ 2638 が類題らしい。