数学の力

京大生が数学の定理・公式の証明や入試問題の解説をするブログ.

プロジェクトオイラー 76. 〜Counting Summations〜


スポンサードリンク

No.76 Counting Summations

問題.

5は正整数の和として:\begin{align*}
&4+1\\
&3+2\\
&3+1+1\\
&2+2+1\\
&2+1+1+1\\
&1+1+1+1+1
\end{align*}の6通りに書ける.では,100は正整数の和として何通りに書けるか.


考え方とプログラム例.(c++)

動的計画法です.先に問題77. の記事を書きましたが,考え方はほとんど同じです.

整数 n k以下の正整数の和として表す方法の個数を f(n, k)通りとすると,以下の漸化式が成り立つ:

 \begin{align*}
 f(n, k) &=\begin{cases}
  1,&k=1,\\
  f(n, k-1),&k>n,\\
  f(n, k-1) + g(n-k, k),&k\leq n.
 \end{cases}
\end{align*}

 k\leq nの場合について,整数 kを使わない場合が f(n, k-1)通り,整数 kを使う場合が f(n-k, k)通りです.

以下がプログラム例です.メモ化再帰?を使ってみました.

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

vector<vector<int>> F(101, vector<int>(100, 0));

ll f(int n, int k){
	ll ret = 0;
	if(F[n][k] > 0)
		return F[n][k];
	if(n - k >= 0)
		ret += f(n-k, k);
	ret += f(n, k-1);
	F[n][k] = ret;
	return ret;
}

int main(){
	for(int n = 0; n <= 100; n++)	F[n][1] = 1;
	cout << f(100, 99) << endl;
	return 0;
}