51Nod 1201 整数划分 (经典dp)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1201
题意不多说了。
dp[i][j]表示i这个数划分成j个数的情况数。
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]
前者表示将i - 1划分为j个数,然后j个数都+1 还是不重复
后者表示将i - 1划分为j - 1个数,然后j - 1个数都+1,再加上1这个数
普通的dp是n^2的,但是可以发现1 + 2 + ... + m = n , (1 + m)*m = n * 2,j只要遍历sqrt(n * 2)个就好了。所以复杂度为n*sqrt(n*2)
1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <ctime> 10 #include <list> 11 #include <set> 12 #include <map> 13 using namespace std; 14 typedef long long LL; 15 typedef pair <int, int> P; 16 const int N = 5e4 + 5; 17 int dp[N][350], mod = 1e9 + 7; 18 19 int main() 20 { 21 int n; 22 while(~scanf("%d", &n)) { 23 memset(dp, 0, sizeof(dp)); 24 dp[0][0] = 1; 25 for(int i = 1; i <= n; ++i) { 26 for(int j = 1; j*j <= i*2; ++j) { 27 dp[i][j] = (dp[i - j][j] + dp[i - j][j - 1]) % mod; 28 } 29 } 30 int ans = 0; 31 for(int i = 1; i <= n; ++i) { 32 ans = (ans + dp[n][i]) % mod; 33 } 34 printf("%d\n", ans); 35 } 36 return 0; 37 }