いい感じに約数の個数を数える必要がある。
概要
- 正整数
が与えられる。
の約数の個数を
とする。
を
から
まで動かし、
の和を求める
解くときに考えた内容
N基準の約数表を考える
の値を
の約数分用意すればいいので、こんな感じのテーブルが欲しい。
(実際の約数は必要ないんだけど、個数が分かれば)
このテーブルが得られれば、列名がの値を全て合計すれば目的の計算になる。(
* 約数の数 )
|
|
---|---|
1 | 1 |
2 | 1 |
2 | 2 |
3 | 1 |
3 | 3 |
4 | 1 |
4 | 2 |
4 | 4 |
だけども、をベースにすると、結局Nのループの中で、約数列挙をするので
。工夫しても
なので
で厳しい。
約数基準の約数表を考える(定数倍の考え方)
これを視点をかえて 基準で考えてテーブルを作る。
これは、 から
以内で、約数
はどの
のときに約数になるか考えることができる。
|
|
---|---|
1 | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
2 | 2 |
2 | 4 |
3 | 3 |
4 | 4 |
として、もう少し長く書く
|
|
---|---|
1 | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
1 | 5 |
1 | 6 |
1 | 7 |
1 | 8 |
1 | 9 |
1 | 10 |
2 | 2 |
2 | 4 |
2 | 6 |
2 | 8 |
2 | 10 |
3 | 3 |
3 | 6 |
3 | 9 |
4 | 4 |
4 | 8 |
5 | 5 |
5 | 10 |
6 | 6 |
7 | 7 |
8 | 8 |
9 | 9 |
10 | 10 |
これも同様に、列名がの値を全て合計すれば目的の計算になる。これを出力するときは、先ほどよりも計算量を少なくできる。
上記の表をみると、以内の
の定数倍が表にに存在していることが理解できる。
を
から
まで回したときの計算量は
となり、括弧内は調和級数なので
であるので、全体では
しかし、これをそのままコードにしてもTLEになる。でもアウトなのかもしれない。(これを通すにはさらなる高速化をするためにNumbaやCythonを使うなどする必要があるみたい。これはこれで使い方を理解しておく必要はある。特にNumbaは理解を深めておこう。)
定数倍であることから等差数列の和と考える
で、どうするかというと、
結局の範囲内の定数倍だけなら等差数列の和で考えればいいぢゃん!
の範囲の定数倍の個数は
を1から
で割り算した時の商であることを利用する。
商をとすると
コード
n = int(input()) ans = 0 # 定数倍かつ等差数列の和。これなら通るO(N) for a in range(1, n+1): # yはnまでにおける約数aの候補数 y = n // a ans += (y+1) * y * a // 2 print(ans) # # 論外パターン O(N**2) # for N in range(1, n+1): # for i in range(1, n+1): # if N % i == 0: # ans += N # i += 1 # print(ans) # # 定数倍で考える O(NlogN) # これ通らないのは辛い。。。 # for a in range(1, n+1): # for N in range(a, n+1, a): # ans += N # print(ans)