51nod 1201 整数划分(dp)

来源:互联网 发布:舟山淘宝代运营诈骗案 编辑:程序博客网 时间:2024/05/24 06:48

看到这个题目首先想到了划分数,即把n划分成m个整数的加和(包括重复的数字,如3=1+1+1),然后确定数字n如果不重复,最多可以划分的位数,例如:1+2+3+4+5=15,则6<= n <10最多可以划分为3位,10 <= n < 15最多可以划分成4位。确定了最大划分的维数,剩下的就是去掉重复的数字了,然后就没有然后了。看了下讨论里,dp[i][j] = dp[i][j-i]+dp[i-1][j-i],dp[i][j]代表把数字j划分成i个不同整数的和。
dp[i][j-i]是把j-i划分成i个不同的整数,也就是dp[i][j]个不同的整数每个数减掉1。dp[i-1][j-i]是把j-i划分成i-1个数,然后这i-1个数每个数加上1,然后在单独加上一个额外的1,就是dp[i][j],我们可以从这两个状态转移到dp[i][j],加上就好了。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 50050;int sum[400];int dp[350][MAXN];int slen = 320;int m;const int mod = 1e9+7;void init(){    for(int i = 1; i <= slen; ++i)        sum[i] = sum[i-1] + i;}int main(){    init();    int n;    scanf("%d",&n);    int *p = lower_bound(sum+1,sum+slen+1,n);    if(*p == n)        m = p - sum;    else        m = p - sum - 1;    //现在就是求把n划分成m个不同的整数    dp[0][0]=1;    for(int i = 1; i <= m; ++i)    {        for(int j = 0; j <= n; ++j)        {            if(j-i >= 0)                dp[i][j] = (dp[i][j-i]+dp[i-1][j-i])%mod;        }    }    int res = 0;    for(int i = 1; i <= m; ++i)        res = (res+dp[i][n])%mod;    printf("%d\n",res);    return 0;}
原创粉丝点击