终于刷了道还算上的了台面的题了 . . . . . .
给你N个方块,让你排成M(M >= 2)列,每列的块数Si要满足(Si < Si+1,Si >=1)。问一共有多少种排列方案。
首先需要预处理出排成M列所需要的最少的块数,即 pre[ M ] = 1 + 2 + 3 + ... + M-1 + M。
然后对于确定的N,M的取值需满足 2 <= M && pre[M] <= N。
设 M 的最大取值为Max。
然后我们计算出把 N-pre[ i ] 放到 i (i∈[2,Max] )列的情况就可以了,放得时候要满足题目的大前提。
话说记忆化搜索好唬人哇。搜索的外表,DP的内心。 。 。
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <stack> #pragma comment(linker, "/STACK:1024000000"); #define LL long long int #define ULL unsigned long long int #define _LL __int64 #define INF 0x3f3f3f3f using namespace std; _LL dp[35][501]; int pre[41]; _LL dfs(int n,int m) { if(dp[n][m] != -1) return dp[n][m]; if(n > m || n == 0 || m == 0) dp[n][m] = 0; else if(n == m || n == 1) dp[n][m] = 1; else { dp[n][m] = 0; for(int i = n; i >= 1 ;--i) { dp[n][m] += dfs(i,m-n); } } return dp[n][m]; } int main() { _LL ans = 0; int n,i,j; scanf("%d",&n); for(i = 2,pre[1] = 1;i <= 40; ++i) { pre[i] = pre[i-1] + i; } memset(dp,-1,sizeof(dp)); for(i = 1;n >= pre[i]; ++i) ; for(--i;i >= 2; --i) { for(j = i;j >= 1; --j) ans += dfs(j,n-pre[i]); } printf("%I64d\n",ans); return 0; }
原文:http://blog.csdn.net/zmx354/article/details/19806225