ural 1017. Staircases(dp数的划分)

题意:

n块砖块,按照从小到大的顺序(可以不连续)排成一堆堆,计算有多少种排列方法

分析:(待补。。。)

     dp[k][n]表示将数n划分成若干个不相等的数,并且划分的数都大于等于k,
由推导可知:
划分成最小大于k的:
    dp[k+1][n]
划分成最小等于k的:
    dp[k+1][n-k]
所以状态转移方程:dp[i][j]=dp[i+1][j]+dp[i+1][j-i];
注意!最后结果是dp[1][n]表示将n划分成若干不等且大于等于1的
但是题目要求阶梯大于等于2个,所以最后要减去只有一个阶梯的情况
就是n划分成一块:n划分为n所以减一
    ans=dp[1][n]-1;

/*******************************************************************************************************************/

转自:http://www.cnblogs.com/skyivben/archive/2009/03/02/1401728.html

数学背景

这道题目涉及到数的分划,属于组合数学数论的研究领域。

1、数 n 的分划(partition)是将 n 表示成任意多个正整数之和的形式。例如,数 5 的分划如下:

  1. 5
  2. 4 + 1
  3. 3 + 2
  4. 3 + 1 + 1
  5. 2 + 2 + 1
  6. 2 + 1 + 1 + 1
  7. 1 + 1 + 1 + 1 + 1

用 p(n) 来记 n 的分划的个数,这样就有 p(5) = 7。

为了求解 p(n),我们引入一个中间函数 p(k, n),表示数 n 的最小被加数不小于 k 的分划的个数。对于给定的 k 值,p(k, n) 正好分为以下两类:

  1. 最小被加数等于 k
  2. 最小被加数大于 k

满足第一个条件的分划的个数是 p(k, nk)。 这是因为,让我们想象数 nk 的最小被加数不小于 k 的分划,然后将 "+ k" 附加每一个分划后面,就得到数 n 的最小被加数等于 k 的分划。以 n = 5, k = 1 为例,数 4 的最小被加数不小于 1 的分划是43 + 12 + 22 + 1 + 11 + 1 + 1 + 1,即 p(k, nk) =p(1, 4) = 5。然后,将 "+ 1" 附加在这 5 个分划后面,就得到数 5 的最小被加数等于 1 的分划:4 + 13 + 1 + 12 + 2 + 12 + 1 + 1 + 11 + 1 + 1 + 1 + 1

满足第二个条件的分划的个数是 p(k + 1, n) 。以 n = 5, k = 1 为例,数 5 的最小被加数大于 1 的分划是53 + 2,即 p(k + 1, n) =p(2, 5) = 2。

也就是说,p(1, 5) = p(2, 5) + p(1, 4)。因此:

  • p(k, n) = 0  如果 k > n
  • p(k, n) = 1  如果 k = n
  • p(k, n) = p(k+1, n) + p(k, n-k)  其它情况

这样,就可以递归地求解 p(k, n),其部分值见下表:

 k
12345678910
n11000000000
22100000000
33110000000
45211000000
57211100000
611421110000
715421111000
822732111100
930842111110
10421253211111

最后,p(n) = p(1, n)

 

2、现在,让我们的来考虑 将 n 分成不相等的正整数之和的分划。例如,数 8 的分划如下:

  1. 8
  2. 7 + 1
  3. 6 + 2
  4. 5 + 3
  5. 5 + 2 + 1
  6. 4 + 3 + 1

用 q(n) 来记 n 的分划的个数,这样就有 q(8) = 6。

为了求解 q(n),我们引入一个中间函数 q(k, n),表示数 n 的最小被加数不小于 k 的分划的个数。对于给定的 k 值,q(k, n) 正好分为以下两类:

  1. 最小被加数等于 k
  2. 最小被加数大于 k

满足第一个条件的分划的个数是 q(k + 1, nk)。 这是因为,让我们想象数nk 的最小被加数大于 k 的分划,然后将 "+ k" 附加每一个分划后面,就得到数 n 的最小被加数等于 k 的分划。以 n = 8, k = 1 为例,数 7 的最小被加数大于 1 的分划是75 + 24 + 3,即 q(k + 1,nk) = q(2, 7) = 3。然后,将 "+ 1" 附加在这 3 个分划后面,就得到数 8 的最小被加数等于 1 的分划:7 + 15 + 2 + 14 + 3 + 1

满足第二个条件的分划的个数是 q(k + 1, n) 。以 n = 8, k = 1 为例,数 8 的最小被加数大于 1 的分划是86 + 25 + 3,即 q(k + 1,n) = q(2, 8) = 3。

也就是说,q(1, 8) = q(2, 8) + q(2, 7)。因此:

  • q(k, n) = 0  如果 k > n
  • q(k, n) = 1  如果 k = n
  • q(k, n) = q(k+1, n) + q(k + 1, n-k)  其它情况

这样,就可以递归地求解 q(k, n),其部分值见下表:

 

 k
12345678910
n11000000000
21100000000
32110000000
42111000000
53211100000
64211110000
75321111000
86321111100
98532111110
1010532111111

 

最后,q(n) = q(1, n)

 

 

#include  <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;

ll dp[1003][1003];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            dp[i][i]=1;
        for(int i=n-1;i>=1;i--)
        {
            for(int j=i+1;j<=n;j++)
                dp[i][j]=dp[i+1][j]+dp[i+1][j-i];
        }
        printf("%I64d\n",dp[1][n]-1);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值