1. 程式人生 > >51nod 1201:整數劃分 超級好的DP題目

51nod 1201:整數劃分 超級好的DP題目

基準時間限制:1 秒 空間限制:131072 KB 分值: 80 難度:5級演算法題  收藏  關注 將N分為若干個不同整數的和,有多少種不同的劃分方式,例如:n = 6,{6} {1,5} {2,4} {1,2,3},共4種。由於資料較大,輸出Mod 10^9 + 7的結果即可。 Input
輸入1個數N(1 <= N <= 50000)。
Output
輸出劃分的數量Mod 10^9 + 7。
Input示例
6
Output示例
4

這個DP想得真叫我累啊,還想不出來。後來問了夾克老師,發現這個DP真是經典啊。

用dp[i][j]表示j個數組成i的個數。那麼對於dp[i][j]每一個j來說,注意是對於每一個j來說,來源就是兩個,一個就是插入j時的dp[i-j][j-1]個數。

然後就是因為要不同整數,不同的來源在哪裡,就是將[i-j][i](其含義是i個數組成了i-j)中的每一個數加1,這點這是奇妙啊,就組成了dp[i][j]的剩餘部分。

所以dp[i][j]=dp[i-j][j]+dp[i-j][j-1]

這個題真是好題。

程式碼:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;

const int maxn = 50000 + 100;
const int mod = 1e9 + 7;
int dp[maxn][350];

int main()
{
	//freopen("i.txt","r",stdin);
	//freopen("o.txt","w",stdout);

	int n;
	scanf("%d", &n);
	dp[0][0] = 1;
	for (int i = 1; i<350; i++)
	{
		for (int j = 0; j <= n; j++)
		{
			if (j - i >= 0)
				dp[j][i] = (dp[j - i][i] + dp[j - i][i - 1]) % mod;
		}
	}
	int ans = 0;
	for (int i = 1; i<350; i++)
		ans = (ans + dp[n][i]) % mod;
	cout << ans << endl;

	return 0;
}