# -*- coding: utf-8 -*- import time prs =[]; vh =[] def f1(zn, pi): if zn==0: print("\t", vh) return 1 rtn = 0 for i in range(pi, 2019): if prs[i] > zn: break vh.append(prs[i]) rtn += f1(zn - prs[i], i) vh.pop() return rtn def eratos(su): #ふるい pr = [True if i&1 else False for i in range(su+10)] pr[1], pr[2] = False,True sq = int(su**0.5) for i in range(3, sq+1, 2): if not pr[i] : continue for j in range(i*i,su+1,i+i): pr[j] = False for i in range(su+1): if pr[i]: prs.append(i) #print(prs) ## f4mに比べればコンパクトだけど、分かりにくくトリッキーな"配列一つ回し" def f4(tgt, lpr, mxs): dp = [0] *(tgt +10); dp[0] =1 for i in prs: if i > lpr: break for j in range(tgt, i*(mxs+1)-1,-1): #減算を先に 後ろからやる dp[j] -= dp[j-i*(mxs+1)] # 上の2行をカットすれば 3)用のスッキリ解答 for j in range(i, tgt+1): #加算は減算後で 前から累積する感じ dp[j] += dp[j-i] return dp[tgt] ## f4よりはわかりやすい(?)が、少し重い"配列二つ回し" ## nxt=i+1,cur=iに換えてメモリー大食い dp[素数の数][目標数]形式にもできる def f4m(tgt, lpr, mxs): dp = [[0] * (tgt+2 ) for _ in range(2)] cur, nxt = 0 , 1 dp[cur][0] =1 for i,p in enumerate(prs): if p > lpr: break for j in range(tgt+1): dp[nxt][j] = dp[cur][j] + (dp[nxt][j-p] if j>=p else 0) \ - (dp[cur][j - p*(mxs+1)] if j >= p*(mxs+1) else 0) #db[i+1][j] = dp[i][j] + dp[i+1][j-p] - dp[i][j-p*(mxs+1)] 要約のみ cur, nxt = nxt, cur return dp[cur][tgt] ## もっとわかりやすいが、この3重ループで今回の制約(11*201931*2019)は無理 def f4x(tgt, lpr, mxs): dp = [0] *(tgt +10); dp[0] =1 for i in prs: if i > lpr: break for j in range( tgt,-1,-1): for k in range(1, mxs+1): if j+k*i > tgt: break dp[j + k*i] += dp[j] return dp[tgt] eratos(2019) print("1)") print(" 合計 %d 通り" %f1(19, 0)) print("2)\t", f4m(31, 31, 31)) print("3)\t", f4(2019, 2019, 2019)) print("4)\t", f4(201931, 31, 2019)) #print( "\t", f4m(201931, 31, 2019)) print( "\n","-" * 10, " speed test f4?(2019,1500,400) ", "-" * 10) for i,pg in enumerate([f4, f4m, f4x]): t1 = time.time() print(pg,"\t->", pg(2019,1500,400)) print(" %.4fsec" %(time.time() - t1))
Standard input is empty
1) [2, 2, 2, 2, 2, 2, 2, 2, 3] [2, 2, 2, 2, 2, 2, 2, 5] [2, 2, 2, 2, 2, 2, 7] [2, 2, 2, 2, 2, 3, 3, 3] [2, 2, 2, 2, 3, 3, 5] [2, 2, 2, 2, 11] [2, 2, 2, 3, 3, 7] [2, 2, 2, 3, 5, 5] [2, 2, 2, 13] [2, 2, 3, 3, 3, 3, 3] [2, 2, 3, 5, 7] [2, 2, 5, 5, 5] [2, 3, 3, 3, 3, 5] [2, 3, 3, 11] [2, 3, 7, 7] [2, 5, 5, 7] [2, 17] [3, 3, 3, 3, 7] [3, 3, 3, 5, 5] [3, 3, 13] [3, 5, 11] [5, 7, 7] [19] 合計 23 通り 2) 111 3) 576202207044176168646563 4) 13683621769893119094927207253137 ---------- speed test f4?(2019,1500,400) ---------- <function f4 at 0x2b30f8b55c80> -> 576199462419913237080484 0.0381sec <function f4m at 0x2b30f8b55d08> -> 576199462419913237080484 0.1354sec <function f4x at 0x2b30f8b55d90> -> 576199462419913237080484 1.0224sec