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;}
阅读全文
0 0
- [DP 数论] 51Nod 1201 整数划分
- 51nod 1201 整数划分 dp
- 51nod 1201 整数划分(dp)
- 【dp】51nod 1201 整数划分
- 51 nod 1201 整数划分(dp)
- 51nod 1201:整数划分 超级好的DP题目
- [51nod 1201]整数划分
- 51nod 1201 整数划分
- 51nod-1201 整数划分
- 51Nod-1201-整数划分
- 51nod 1201 整数划分
- 【51Nod 1201】 整数划分
- 【51nod 1201】 整数划分
- 51Nod 1201 整数划分
- 51NOD 1201 整数划分
- 整数划分 51Nod
- 【51nod 1201】【DP + 思维】整数划分【将N分为若干个不同整数的和,求划分数】
- 51nod 1201[整数划分] 1259[整数划分V2] 1597 [有限背包计数问题]
- [经验]tableview的contentSize默默自己在变。
- SSLHandshakeException: Received fatal alert: handshake_failure
- leetcode 29
- Java基础之运算符
- 数值分析常用的几个小程序C++实现
- 51nod 1201 整数划分(dp)
- cordova开发教程
- NandFlash ECC 校验算法原理与实现
- android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a vi
- Android打开系统相册页面
- 一些小知识点
- 二叉树的递归遍历以及非递归遍历
- ubuntu 14.04 开启root登录
- 面试(六) 多线程