Python3で解く AtCoder Beginner Contest 172 D - Sum of Divisors
いい感じに約数の個数を数える必要がある。
概要
- 正整数が与えられる。
- の約数の個数をとする。
- を からまで動かし、の和を求める
解くときに考えた内容
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)