[ABC243] G - Sqrt

[Q] https://atcoder.jp/contests/abc243/tasks/abc243_g

本番ではGまで目を通せなかったけど、見返したらいける問題。

X=10000を考えてみる。

A(10000)
= A(100) + A(99) + A(98) + ... + A(1)

もう少し分解してみる。
A(1) = A(1)
A(2) = A(1)
A(3) = A(1)
A(4) = A(2) + A(1)
A(5) = A(2) + A(1)
...
A(8) = A(2) + A(1)
A(9) = A(3) + A(2) + A(1)
...
A(100) = A(10) + A(9) + A(8) + ... + A(1)

A(1) ~ A(100)の個数は、
A(1)が100個 // 100 - 1^2 + 1
A(2)が97個 // 100 - 2^2 + 1
A(3)が92個 // 100 - 3^2 + 1
...
A(10)が1個 // 100 - 10^2 + 1
ずつあることがわかる。

A(10000) =  A(1) * (100 - 1^2 + 1)
          + A(2) * (100 - 2^2 + 1)
          + ...
          + A(10) * (100 - 10^2 + 1)

ということは、A(1) ~ A(10)の値をゴリゴリ出しておけば、求められる。

A(1) = 1
A(2) = 1
A(3) = 1
A(4) = A(2)+A(1) = 2
A(5) = 2
...
A(9) = 3
A(10) = 3
だ。

A(10000)を求めるのに、A(10)まで見ればいい。
A(X) を求めるのに、A(√√X) まで見ればいい。
A(9e18)を求めるのに、A(54772.255) まで見ればいい。

ので、手元で計算するのは54773まででいけそう。

実装


ll D[54780];

// D[54773]まで、Xを直接計算する。
void init() {
 D[1] = 1;
 ll base = 2;
 for (ll i = 2; i < 54774; ++i) {
   D[i] = D[i - 1];
   if (base * base == i) {
     D[i] += D[base];
     ++base;
   }
 }
}

int main() {
 cincout();

 init();
 ll T;
 cin >> T;
 rep(t, T) {
   ll X;
   cin >> X;
   // sqrtだと死ぬ
   X = sqrtl(X);
   ll ans = 0;
   ll cnt = 1;
   while (1) {
     ll items = X - cnt * cnt + 1;
     if (items < 0) break;
     ans += items * D[cnt];
     ++cnt;
   }
   cout << ans << endl;
 }
}

https://atcoder.jp/contests/abc243/submissions/30143517

Q. 1WAくらう?
A. sqrtだと死ぬ。

sqrt(9000000000000000000) = 3000000000
だが、
sqrt(8999999999999999999) = 3000000000
になってしまう。

sqrtl(9000000000000000000) = 3000000000
だが、
sqrtl(8999999999999999999) = 2999999999
になる。


sqrtfloatだから、6桁までしか保証されず、3000000000(9桁)は壊れる。
sartlはdoubleだから、15桁まで保証される。


この記事が気に入ったらサポートをしてみませんか?