NYOJ 651 —— n划分为2个以上不同正整数的划分个数

Posted SuperChan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NYOJ 651 —— n划分为2个以上不同正整数的划分个数相关的知识,希望对你有一定的参考价值。

Cut the rope

时间限制:1000 ms  |  内存限制:65535 KB
描述

We have a rope whose length is L. We will cut the rope into two or more parts, the length of each part must be an integer, and no two parts have the same length.
  Your task is to calculate there exists how many results after the cutting. We say two results are different if and only if there is at least one part, which we can find in one result but can not find in the other result

输入
There is an integer T (1 <= T <= 50000) in the first line, which indicates there are T test cases in total.
  For each test case, there is only one integer L (1 <= L <= 50000) which has the same meaning as above.
输出
For each test case, you should output the correct answer of the above task in one line.
  Because the answer may be very large, you should just output the remainder of it divided by 1000000 instead
样例输入
3
2
3
6
样例输出
0
1
3

  这题对时间和空间的限制很高,所以,我们要尽力优化才行。

  一般的,求n划分为不同正整数的划分个数,这个问题可以通过dp来解决,定义dp[i][j]为i划分为不大于j的划分个数。但是,这里会遇到一个很棘手的问题:1 ≤ n ≤ 50000,所以如果按照这种状态的定义,空间、时间复杂度达到25*108,时间、空间都会超过限制!

  所以,一般的做法行不通。换一个思路:题目其实也是在求n划分为2、3、...个不同正整数的划分个数之和。

  求n划分为k个正整数的划分个数,这个问题也可以用dp来解决:定义dp[i][j]为i划分为j个不同正整数的划分个数。

  i的取值范围仍为[1, 50000],那么j的范围呢?即,i最多可以被划分为多少份呢?

  假设我们将i划分成了j份,那么在i取最小的情况下,i=1+2+...+j (划分的每个元素都要不相同) = (1+j)*j/2。因为i ≤ 50000,所以j最多取到316,而不可能分得更多了,再分就要出现相同的了。故,j ≤ 316

  时间、空间大小降为316*50000=1.58*107,因为系数较小,可以AC

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;

const int MAXN = 50005;
const int MOD = 1000000;
int dp[MAXN][317];

void init()
{
    dp[1][1] = 1;
    for(int i=2; i<316; i++)
        dp[1][i] = 0;
        
    for(int i=2; i<MAXN; i++) {
        for(int j=1; j<317; j++) {
            if(j>=i)    dp[i][j] = 0;
            else    dp[i][j] = (dp[i-j][j-1] + dp[i-j][j])%MOD;
        }
    }
}
 

int main ()
{
    init();
    
    int T, n, ans;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        ans = 0;
        for(int i=2; i<317; i++)    ans = (ans + dp[n][i]) % MOD;
        printf("%d\n", ans);
    }
    return 0;
}

 

以上是关于NYOJ 651 —— n划分为2个以上不同正整数的划分个数的主要内容,如果未能解决你的问题,请参考以下文章

NYOJ 746 - 正整数n划分为m段,求m段的最大乘积 区间DP

NYOJ 1103 —— m划分为n个正整数的个数

NYOJ 571 —— 各种划分数

整数划分问题(递归)

将正整数n表示成k个正整数的和(不计各数次序),称为正整数n分为k部分的一个划分,两个划分中,如果各加

NYOJ - 整数划分