質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

6回答

3716閲覧

PE12 三角数の約数の数を求める処理が遅い

opyon

総合スコア1009

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

1グッド

1クリップ

投稿2018/08/14 09:23

編集2018/10/31 05:48

###追記
解決したのは数ヶ月前でしたが別言語で改めて実装してみたところ
@swordoneさんの回答に近い実装で今のところ最速となりました。
当時はまだ理解が足りていなかったのでBAを変更させていただきました。

要点としては・・・
1.約数の個数は素因数分解で求める
2.1つ前で求めた解をキャッシュして使う ※@swordoneさんコードのlow,high変数

約数の個数と素因数分解の参考情報
約数の個数の公式と平方数の性質
素因数分解と約数の個数と総和の求め方を説明!|数学勉強法

結果が出るまで時間が掛かり過ぎる

参考にした例題元 リンクURL
結果が出るまで10分以上掛かり何度も中断しているので改善点などアドバイス頂けたら幸いです。
※ソースコードは結果が即出るように変数を設定しています。

ソースコード

java

1 /** 2 * 3 * 問題 https://projecteuler.net/problem=12 4 * ※以下Google翻訳 5 * 三角数のシーケンスは、自然数を加算することによって生成されます。 6 * したがって、7 番目の三角形の数は1 + 2 + 3 + 4 + 5 + 6 + 7 = 28となります。 7 * 最初の10の項は次のようになります。1、3、6、10、15、21、28、36、45、55、... 8 * 最初の7つの三角数の要素をリストアップしましょう。 9 * 10 * 1:1 11 * 3:1,3 12 * 6:1,2,3,6 13 * 10:1,2,5,10 14 * 15:1,3,5,15 15 * 21:1,3,7,21 16 * 28:1,2,4,7,14,28 17 * 18 * 28が5つの除数を持つ最初の三角形の数であることが分かります。 19 * 最初の三角形の数には何百もの約数がありますか? 20 * 21 * 原文:What is the value of the first triangle number to have over five hundred divisors? 22 * 23 * ---以下推測--- 24 * 25 * 28: 1,2,4,7,14,28 26 * 2,4,7,14,28 ===>>> 5 27 * 28 * over five hundred divisors? 29 * 約数が500以上の三角数を求める? 30 * 31 */ 32 public static void main(String[] args) { 33 34 long start = System.currentTimeMillis(); 35 36// func(5, 1); //0ms //Answer:28 37// func(300, 1); //2245ms //Answer:2162160 38 func(500,12375); //205ms //Answer:76576500//即答用 39// func(500,1); //未達 40 41 long end = System.currentTimeMillis(); 42 System.out.println((end - start) + "ms"); 43 System.out.println(); 44 45 }

java

1 /** 2 * num個以上の約数を持つ最初の三角数を求める 3 * @param num : 約数の数 4 * @param cnt : 探索開始初期値1 5 */ 6 static void func(int num, int cnt) { 7 8 //探索開始初期値 9 int counter = cnt; 10 // 即答用 11 // int counter = 12375; 12 // ログ c:12375 t:76576500 d:575 13 // Answer:76576500 14 15 while (true) { 16 17 //三角数 18 int triangle = 1; 19 20 for (int i = 2; i <= counter; i++) { 21 triangle += i; 22 } 23 24 //奇数はスキップ 25 if (triangle % 2 == 1) { 26 counter++; 27 continue; 28 } 29 30 //約数 31 int divisors = 0; 32 33 for (int i = 2; i <= triangle; i++) { 34 if (triangle % i == 0) { 35 divisors++; 36 } 37 } 38 39 //ログ 40// System.out.println("Log c:" + counter + " t:" + triangle + " d:" + divisors); 41 42 //出力 43 if (divisors >= num) { 44 System.out.println("Answer:" + triangle); 45 return; 46 } 47 counter++; 48 } 49 }

出力結果(※即答用に変数を指定した場合)
Answer:76576500
204ms


試したこと

java

1 //奇数はスキップ 2 if(triangle % 2 == 1) { 3 counter++; 4 continue; 5 }
  • 大きい解は偶数のみなので暫定的に奇数はスキップするようにしたところ300個探索で約2倍速度upしました。
  • counter探索開始初期値を変更することで解を即答出来るようにしました。

わからないこと

  • 例題なので答えがすぐに表示される解法があるのではないか
  • ボトルネックになっているのはどこなのか

初歩的な総当たりループで探索し初期値を手動で変更などしているので本来の求め方では無いと思います。
指数倍的に時間が掛るのはループに原因があるのかなと思いますがアドバイスやヒントなど頂けましたら幸いです。

x_x👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/08/14 10:45

等差数列の和は (最小値+最大値)*(最大値/2)でだせるからループなんて必要ないんだけどね
opyon

2018/08/14 11:23

ありがとうございます。n(n+1)/2の公式を取り入れ作り直すとこまで出来たので、追加でその公式も考慮してみたいと思います。
opyon

2018/08/14 11:31

と思ったのですが、n(n+1)/2の公式が三角数ですでに等差数列の和ですよね? 約数の個数を求めるのに(例えば6なら1,2,3,6の計4個) 三角数=等差数列の和なので敢えて使うところが無いのかなと思っています。 こちらの勘違いだったらご指摘ください。
退会済みユーザー

退会済みユーザー

2018/08/14 11:33

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
退会済みユーザー

退会済みユーザー

2018/08/14 11:33

この部分
退会済みユーザー

退会済みユーザー

2018/08/14 11:34

三角数を求めてる場所がループで求めてるからループする必要ないってこと
opyon

2018/08/14 12:16

はいそうです。その代りにn(n+1)/2を公式に取り入れて作り直したのでご確認ください。コメントした時にはコード掲載してなかったので説明が分かりづらかったと思います。すみません。
guest

回答6

0

約数の個数の性質として、「互いに素なabについて、a*bの約数の個数は、aの約数の個数×bの約数の個数に等しい」ということがあります。

三角数はn(n+1)/2となりますが、nn+1は互いに素なので、「nn+1のうち、奇数の方」と「nn+1のうち、偶数を2で割ったもの」で分けて約数の個数を計算して、それをかければ、一気に計算量を減らせます。

java

1 static int dividors(int num) { 2 int divisors = 1; 3 4 for (int i = 2; i <= num; i++) { 5 if (num % i == 0) { 6 divisors++; 7 } 8 } 9 return divisors; 10 } 11 12 static void func(int num, int cnt) { 13 for(int n = cnt; ;++n) { 14 int x, y; 15 if(n % 2 == 1) { 16 x = n; 17 y = (n + 1) / 2; 18 } else { 19 x = n / 2; 20 y = n + 1; 21 } 22 if(dividors(x) * dividors(y) > 500) { 23 System.out.println("Answer:" + ((long)x * y)); 24 return; 25 } 26 } 27 } 28

paiza.ioで実行した結果

投稿2018/08/14 10:15

編集2018/08/14 10:25
maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

opyon

2018/08/14 10:32

ありがとうございます。 公式を利用した計算を考えてみます。
opyon

2018/08/14 13:41

ベストアンサーとても迷いましたが@Stars1024さんに送りました。 一人にしか送れないのがとても惜しいです。 奇数偶数で分けたり、平方根までの計算だったり、数学やアルゴリズムに慣れている方のアドバイスはとても参考になります。 ありがとうございました。
guest

0

参考にした問題のページにアクセスして、実際に問題を見たところ,「約数の個数が500を超える最小の三角数を求める」と書いてあったのでそれを解くコードを作成しました。

約数の個数を求めるのに工夫したところ

例えば、nが2で割り切れたら、n / 2nの約数です。(約数の性質)
つまり、nの平方根の整数部分までの約数の個数を求めそれを2倍すればいいのです。
ここで、注意すべき点はnが平方数の場合です。~~この場合はさらに1加えればいいでしょう。
~~
この場合は平方数の部分が重複するので1減らす必要があります。

コードはまだ作成していないけれど、他に思いついた方法について

約数の個数を求める方法なら素因数分解して求めるのが一番 はやいと思います。
ただ、まだ実装できていないので、まだそこは考えます。
素因数分解された形に表示するだけならできますが、それぞれの因数の個数を求めるとなると
おそらく配列に素数を順に格納させ、それぞれの個数を数え上げる必要があると思います。
その時の処理速度が気になりますが....

とりあえず、求めたい個数が500を超える最小の三角数を求めることはできたので
その部分のコードを載せておきます。

java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args){ 5 6 Scanner sc = new Scanner(System.in); 7 int i = 1; 8 while(number_divisors(i * (i + 1) / 2) < 500){ 9 i++; 10 } 11 System.out.println(i + "番目の三角数:" + i * (i + 1) / 2); 12 } 13 public static int number_divisors(int n) 14 { 15 int sum = 2; 16 for(int i = 2; i <= Math.sqrt(n); i++){ 17 if(n % i == 0){ 18 sum += 2; 19 } 20 } 21 if(is_square(n)){ 22 sum--; 23 } 24 return sum; 25 } 26 public static boolean is_square(int n) 27 { 28 return n == (int)Math.pow((int)Math.sqrt(n),2); 29 } 30} 31

<実行結果>
12375番目の三角数:76576500

投稿2018/08/14 10:13

編集2018/08/15 12:20
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/08/14 10:14

素因数分解をして約数の個数を求める方法を実装し、もしそちらの方の処理速度が速かったら、そちらを載せます。
opyon

2018/08/14 10:34

ありがとうございます。 公式を利用した計算を考えてみます。 コードはチラ見だけして丸パクリはしないように注意します。 どうしても詰まったらカンニングさせてもらいますね。
opyon

2018/08/14 13:09

@Stars1024さんの平方根まで求め2倍にする方法と、 @maisumakunさんの奇数偶数で分ける方法と、 本質的には同じような意味なのでしょうか? 数学に疎いもので理解が足りずすみません。
opyon

2018/08/14 13:26

よく考えたら奇数偶数で分けてもそれぞれの約数の個数を計算しているので、 試しに平方根まで求め2倍にする方法を実装してみました。 爆速です! コード修正したものを後ほど差し替えておきます。
退会済みユーザー

退会済みユーザー

2018/08/14 14:05

>@Stars1024さんの平方根まで求め2倍にする方法と、 @maisumakunさんの奇数偶数で分ける方法と、 本質的には同じような意味なのでしょうか? 私が書いた「平方根まで求める」は約数の性質を使っており、 maisumakunさんがおっしゃった方法は約数の個数の性質を使っています。 maisumakunさんの回答にもありますが、「互いに素である2つの自然数m,nに対して (mの約数の個数) * (nの約数の個数) = (m*nの約数の個数)」が成り立ちます。 n,n + 1は互いに素であるのですが、 (i) nが偶数 n + 1が奇数 (ii)nが奇数 n + 1が偶数 の2つの場合があります。そのため、「偶数奇数で分ける」必要があります。 結論を言うと、厳密には異なると思います。前述の通り「約数の性質」と「約数の個数の性質」だからです。
opyon

2018/08/14 14:10

なるほどそうですね、数学的に厳密な理解は出来ていませんが、実装してみることで得たことは多いです。 「約数の性質」と「約数の個数の性質」の合わせ技で10分以上でも答えが出なかったものがわずか7msで出るようになりました。 ありがとうございました。
opyon

2018/08/15 07:32

今更なのですが func(500)などの大きい数値なら問題なく答えが出るのですが、 func(5)などの小さい数値で求めると正しい結果が得られないことに気づきました。 @Stars1024さんの「平方根まで求める」部分のコードをそのまま組み込んでも同じなので調べているところです。 ちなみに約数の個数を全ループで探す元の方法に戻すと大丈夫でした。
退会済みユーザー

退会済みユーザー

2018/08/15 07:39

func(5) = 28であっていますよね? 確認したところ私が書いたコードでは 28と出力されました。
opyon

2018/08/15 08:06

@Stars1024さんの全コードをまとめて使うと大丈夫だと思います。 「平方根まで求める」部分のみ利用させて頂くと結果が違うのでこちらの実装方法と使い方が間違っているのだと思います。
opyon

2018/08/15 08:19

@Stars1024さんの全コードで試してみました。n=1,2,3で試すと全て1になります。 n=4で6の結果が出ますので、3までの処理が必要かもしれません。 「平方根まで求める」機能をなんとか自分でも理解して実装してみたいと思います。
x_x

2018/08/15 09:01

> この場合はさらに1加えればいい 引くのでは? 平方根を二重にカウントしているのですよね?
opyon

2018/08/15 13:19 編集

(元が訂正されたので他の方が見る時に誤解の無いように削除しておきます)
x_x

2018/08/15 11:51

number_divisors()のことを言っているのですが…… number_divisors(3) // 2 ……あってる number_divisors(4) // 5 ……3が正しい number_divisors(5) // 2 ……あってる …… number_divisors(12) // 6 ……あってる number_divisors(16) // 7 ……5が正しい
退会済みユーザー

退会済みユーザー

2018/08/15 12:22

すみません。x_xさんのおっしゃる通り平方数の場合は約数がその平方根になるとき重複するので 1減らす必要があります。 最初の平方根までやる部分で for(int i = 2; i <= Math.sqrt(n); i++) と i<=Math.sqrt(n)のように 「<=」不等号に=がついてるためです。見落としていました。 x_xさん、ご指摘ありがとうございます。
退会済みユーザー

退会済みユーザー

2018/08/15 12:23

その個所の訂正はしました。
opyon

2018/08/15 13:32

両者様ともありがとうございます。
opyon

2018/10/31 05:34

検索で見に来た方の為にBAを変更させていただきました。
guest

0

ベストアンサー

三角数は1からnまでの総和なのでn*(n+1)/2で求められます。
1番目:12/2=1
2番目:2
3/2=3
3番目:3*4/2=6
という具合に。

そして約数の個数は、素因数分解できれば、各素因数の個数+1をすべて掛けることで求められます。
また、隣り合った自然数は互いに素なので、その積の約数の個数は各自然数の約数の個数の積になります(maisumakunさんの回答通り)。

これらの事実を利用すれば、各自然数の約数の個数を素因数分解しながら求めることで、高速に求められるかと思います。

java

1private static int numOfDivisor(int n) { 2 if (n < 2) return 1; 3 int answer = 1; 4 5 // 偶数だった場合は2で割る(ビットシフト) 6 if ((n & 1) == 0) 7 n >>= 1; 8 9 // nが√Integer.MAX_VALUE以上の素数だったりすると、この継続条件は良くないが、 10 // 簡単なのでこちらで進める 11 for (int i = 2; i * i <= n; i++) { 12 int count = 0; 13 while (n % i == 0) { 14 n /= i; 15 count++; 16 } 17 answer *= count + 1; 18 } 19 // forを抜けて残ったnが1でないときは、そのnは素数なので1+1=2を掛ける 20 if (n != 1) 21 answer *= 2; 22 return answer; 23}

で、500個以上の三角数を探すのはこういうコード

java

1public static void main(String[] args) { 2 int n = 500; 3 System.out.println(n + "個以上の約数を持つ最初の三角数は" + func(n)); 4} 5 6public static int func(int num) { 7 // 2番目の三角数2*3/2=3に対応する、low:2/2=1の約数の個数1、high:3の約数の個数2 8 int low = 1; 9 int high = 2; 10 int n = 2; 11 while (low * high < num) { 12 n++; 13 low = high; 14 high = numOfDivisor(n + 1); 15 } 16 return n * (n + 1) / 2; 17}

ideoneでの実行結果
0.09秒で解決

投稿2018/08/14 15:02

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

opyon

2018/08/15 05:57 編集

ありがとうございます。 すでに7msで結果出ているのでと思ったのですがコードを読んでみると知らない技法など使っていてとても参考になります。
opyon

2018/10/31 05:34

かなり前の回答ですが・・・ 別言語のC++で改めて速度を追求してみたところ、 こちらの回答に近い実装で最速となりました。(平均で約1ミリ秒) 検索で見に来た方の為にBAを変更させていただきました。
guest

0

python での回答例を web で検索し、速度を比較してみました。

1. https://qiita.com/hoxo_m/items/ad17361b7276f1c6527b
2. http://freak-da.hatenablog.com/entry/20100729/p1
3. https://qiita.com/yukkyo/items/29cd0d4c87ba29819f40
4. https://stackoverflow.com/questions/17743851

どれも 一瞬で終わるレベルですが、 このなかでは 2 番目のものが一番 速そうです。
アルゴリズムを研究して java に移植するとよいと思います。
上のものは "Project Euler 12 python" で google 検索してみつけたものですが、 "Project Euler 12 java" で検索すれば、 java での解をいろいろ見つけることができると思います。

イメージ説明

py12_1.py

python

1# See https://qiita.com/hoxo_m/items/ad17361b7276f1c6527b 2import math 3 4# limit = 5 5limit = 500 6 7def compute_factors(num): 8 factors = [1] 9 if (num == 1): return factors 10 for i in range(2, int(math.floor(math.sqrt(num))) + 1): 11 if(num % i == 0): 12 factors.append(i) 13 factors_rev = list(factors) 14 factors_rev.reverse() 15 for i in factors_rev: 16 fac = num // i 17 if(fac not in factors): 18 factors.append(fac) 19 return factors 20 21triangular_nums = [1] 22factors = [] 23n = 2 24while True: 25 triangular_num = triangular_nums[n - 1 -1] + n 26 triangular_nums.append(triangular_num) 27 factors = compute_factors(triangular_num) 28 if len(factors) >= limit: 29 break 30 n += 1 31 32result = triangular_nums[-1] 33 34print(result) 35print(result == 76576500) 36print(n) 37print(len(factors), factors[:10])

py12_2.py

python

1# http://freak-da.hatenablog.com/entry/20100729/p1 2 3import math 4import sys 5 6fact = {1:1, 2:2} # 約数の個数をキャッシュする辞書 7 8def num_factors(n): 9 if n in fact: return fact[n] 10 11 r = int(math.sqrt(n)) 12 13 num = 0 14 if r * (r + 1) == n: 15 num = num_factors(r) * num_factors(r + 1) 16 else: 17 i = 1 18 while i < r: 19 if n % i == 0: 20 num += 1 21 22 i += 1 23 24 num *= 2 25 if r * r == n: num += 1 26 27 fact[n] = num 28 return num 29 30def main(): 31 n = 2 32 while True: 33 if n % 2 == 0: 34 fn = num_factors(n / 2) * num_factors(n + 1) 35 else: 36 fn = num_factors(n) * num_factors((n + 1) / 2) 37 38 if fn >= 500: 39 print("%d = (%d * %d) / 2, it has %d factors" % (n * (n + 1) / 2, n, n + 1, fn)) 40 return 41 42 fact[n * (n + 1) / 2] = fn 43 44 n += 1 45 46if __name__ == '__main__': 47 main()

py12_3.py

python

1# See Phttps://qiita.com/yukkyo/items/29cd0d4c87ba29819f40 2 3# problem 12 4import math 5import collections 6 7# 数字を素因数分解する 8def trial_division_sqrt(n): 9 prime_count = collections.Counter() 10 for i in range(2, int(math.sqrt(n)) + 2): 11 while n % i == 0: 12 n /= i 13 prime_count[i] += 1 14 if n > 1: 15 prime_count[int(n)] += 1 16 return prime_count 17 18# 約数の個数を求める 19def count_divisor(num): 20 ans_count = 1 21 count_one = 0 22 # 素因数分解して各素数の個数のリストを求める 23 prime_count = trial_division_sqrt(num) 24 25 # 各リスト内の個数をカウント 26 for v in prime_count.values(): 27 if v == 1: 28 count_one += 1 29 else: 30 # 同じ素数が複数個含まれている場合 31 ans_count *= v + 1 32 return ans_count * pow(2, count_one) 33 34ans_num = 0 35count = 0 36divisors = 500 37 38while(True): 39 count += 1 40 ans_num += count 41 if count_divisor(ans_num) > divisors: 42 break 43ans_num

py12_4.py

python

1# See https://stackoverflow.com/questions/17743851 2 3import math 4 5def get_factors(n): 6 return sum(2 for i in range(1, round(math.sqrt(n)+1)) if not n % i) 7 8def generate_triangles(limit): 9 l = 1 10 while l <= limit: 11 yield sum(range(l + 1)) 12 l += 1 13 14def test_triangles(): 15 triangles = generate_triangles(100000) 16 for i in triangles: 17 if get_factors(i) > 499: 18 return i 19 20print(test_triangles())

投稿2018/08/15 04:07

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

opyon

2018/08/15 04:28

ありがとうございます。 検索でここへ辿り着いた方へ参考になると思います。 自分は他言語覚えるほど余裕はないですが他言語覚える時は参考にさせていただきます。
opyon

2018/08/15 04:39

2番が速いとのことでしたのでリンク先の解説読んでみたところ 主に①「三角数の公式」②「公式nの偶数判定」③「公式n+1の再利用」を実装してるようです。 自分もアドバイス頂いた①と②は実装出来ましたが③はまだだったのでやってみます。
opyon

2018/08/15 15:08

2番目を参考に③「公式n+1の再利用」を実装してみましたが、逆に遅くなりました。 7ms⇢136ms 追加したのはmapだけですので全体のコードは省略しますが読み書きでオーバーヘッド?が発生してるのかなと思います。 static HashMap<Integer, Integer> map = new HashMap<>(); 単純に1,3,6,10毎に約数をmap.putして再利用時にmap.getするだけの3行追加しただけです。 再利用の理屈はよくわかったのですが再利用するためにアクセスするより単純計算させておいたほうが速いようです。 また別の機会で改善策として利用できそうなのでとても参考になりました。 ありごとうございました。
guest

0

Javaなど不要。そう、シェル芸ならね!

bash

1$ seq 100000|awk '$0=$1+s,s=$0'|gfactor|awk '{delete a;for(i=2;i<=NF;i++){a[$i]++};s=1;for(i in a){s*=a[i]+1};if(s>=500){print $1,s"個";exit}}' 276576500: 576

なお実行時間

bash

1$ time (seq 100000|awk '$0=$1+s,s=$0'|gfactor|awk '{delete a;for(i=2;i<=NF;i++){a[$i]++};s=1;for(i in a){s*=a[i]+1};if(s>=500){print $1,s"個";exit}}') 276576500: 5763 4real 0m0.080s 5user 0m0.106s 6sys 0m0.016s

投稿2018/08/14 11:31

編集2018/08/14 11:55
hichon

総合スコア5737

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

opyon

2018/08/14 13:00

ありがとうございます。1行?で解を求められるなんて凄いですね。
guest

0

頂いたアドバイスで作り直したところ、かなり改善できました。
ありがとうございました。
※追加で平方根の処理を実装したところ更に改善できました。


java

1 public static void main(String[] args) { 2 long start = System.currentTimeMillis(); 3 4 func(500); 5 6 long end = System.currentTimeMillis(); 7 System.out.println((end - start) + "ms"); 8 } 9 10 static void func(int num) { 11 12 int n = 0; //自然数n 13 int t = 0; //n番目の三角数(総和) 14 15 //約数の個数の性質「互いに素なaとbについて、 16 //a*bの約数の個数は、aの約数の個数×bの約数の個数に等しい」 17 //nとn+1は互いに素なのでnかn+1のどちらかが偶数になる 18 19 int x = 0; //(偶数奇数で分けて偶数の方を2で割る) 20 int y = 0; //(偶数奇数で分けて偶数の方を2で割る) 21 int d = 0; //分けて計算した約数の個数を掛けた総数 22 23 while (d < num) { 24 25 //自然数n 26 n++; 27 28 //三角数の公式 29 //n(n+1)/2 30 31 //n 1 2 3 4 5 6 7 8 9 10 32 //三角数 1 3 6 10 15 21 28 36 45 55 33 //約数  1 2 4 4 4 4 6 9 6 4 34 35 //偶数奇数判定 36 if (n % 2 == 0) { 37 x = n / 2; 38 y = n + 1; 39 } else { 40 x = n; 41 y = (n + 1) / 2; 42 } 43 44 //個別に約数の個数を求め掛け合わせて総数を求める 45 d = getD(x) * getD(y); 46 } 47 48 //ログ出力用 49 t = n * (n + 1) / 2; 50 51 System.out.print("last n:" + (n)); 52 System.out.print(" t:" + t); 53 System.out.print(" d:" + d); 54 System.out.println(); 55 System.out.println("Ans:" + t); 56 } 57 58 //約数の個数を求める 59 static int getD(final int t) { 60 61 int d = 0; 62 63 final int rootT = (int) Math.sqrt(t); 64 65 for (int i = 1; i <= rootT; i++) { 66 if (t % i == 0) { 67 d++; 68 } 69 } 70 71 d *= 2; 72 73 if (t == rootT * rootT) { 74 d--; 75 } 76 77 return d; 78 }

出力結果

last n:12375 t:76576500 d:576
Ans:76576500
0ms

投稿2018/08/14 12:20

編集2018/08/15 15:26
opyon

総合スコア1009

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問