终于刷了道还算上的了台面的题了 . . . . . .
给你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