URAL 1017 Staircases 记忆化搜索

终于刷了道还算上的了台面的题了 . . . . . .

给你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;
}



你可能感兴趣的:(URAL 1017 Staircases 记忆化搜索)