【AtCoder】ABC 428 D - 183184
実行時間制限: 2.5 sec / メモリ制限: 1024 MiB / Difficulty: 1239 / NoviSteps: 1D / 配点: 400 点
問題概要
正整数 に対して を以下で定義する。
- 十進表記の をそれぞれ文字列として解釈しこの順に連結して得られる文字列を とする。 を十進表記の整数として解釈したときの値を とする。
正の整数 が与えられるので、以下を満たす整数 の個数を求めよ。
- は平方数である
ただし、 個のテストケースが与えられるので、それぞれについて答えを求めること。
制約
- 入力される値はすべて整数
考察
まずは、 の値が取りうる範囲を考えよう。
の部分が 桁の数であるとき、 は次のように表せる。
ここで、 が 桁の数であるための条件 :
と、問題文の という条件の共通部分を取ると、 の取りうる範囲は以下の を用いて と表せる。
ただし、 のときはこのような は存在しない。
上記の範囲を が動くとき、 の値の範囲は式から以下のようになる。
あとは、この範囲内で平方数となる整数の個数を求めればよい。
ある正整数 に対して、 以下の平方数の個数は であるという事実を用いると、式の範囲内で平方数となる整数の個数は以下のようになる。
は最大 桁であるから、これを について全て足し合わせたものが求める答えとなる。
実装例
の計算は二分探索でも実装できるが、公式解説のものを拝借して実装すると実質 で計算することができる。
1.#include <bits/stdc++.h>2.using namespace std;3. 4.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)5.#define repe(i, start, end) for (auto i = (start); (i) <= (end); (i)++)6. 7.using ll = long long;8. 9.ll floor_sqrt(ll x)10.{11. ll y = sqrt(x);12. while (y * y > x)13. y--;14. while ((y + 1) * (y + 1) <= x)15. y++;16. return y;17.}18. 19.// ======================================== //20. 21.int main()22.{23. int T;24. cin >> T;25. 26. vector<ll> pow10(11, 1);27. rep(i, 1, 11) pow10[i] = pow10[i - 1] * 10;28. 29. auto solve = [&]() -> ll30. {31. ll C, D;32. cin >> C >> D;33. 34. ll ans = 0;35. repe(k, 1, 10)36. {37. ll l_x = max<ll>(1, pow10[k - 1] - C);38. ll r_x = min<ll>(D, pow10[k] - 1 - C);39. if (l_x > r_x)40. continue;41. 42. ll l_val = pow10[k] * C + C + l_x;43. ll r_val = pow10[k] * C + C + r_x;44. 45. ans += floor_sqrt(r_val) - floor_sqrt(l_val - 1);46. }47. 48. return ans;49. };50. 51. while (T--)52. {53. cout << solve() << endl;54. }55. 56. return 0;57.}
実装時間: 45 分
コメント
公式解説の の実装、頭いいな。





