划分型动态规划 之 CODE[VS] 1039 数的划分 2001年NOIP全国联赛提高组

/*
dp[i][k] := 将整数i分成k份,分法种数
初始化:
	dp[][] = { 0 }
	dp[i][1] = 1
状态方程:
	dp[i][k] = dp[i-1][k-1] + dp[i-k][k]

	思想:(引自byvoid大神的博客:https://www.byvoid.com/blog/noip-allsolutions#.E6.95.B0.E7.9A.84.E5.88.92.E5.88.86)

		每种拆分方案中,最小的数为w,按照w的不同,我们可以把拆分方案分成2类:
			w=1,我们把1除去,则剩余部分正好是i-1拆分成k-1部分,一共有dp[i-1,k-1])个;
			w>1,所有的数都>1,我们把所有的数-1,则正好是i-k拆分成k部分,一共有dp[i-k,k]个。
		根据加法原理,得出以上方程。
答案:
	dp[N][K]
*/
 1 #define _CRTDBG_MAP_ALLOC
 2 #include <stdlib.h>
 3 #include <crtdbg.h>
 4 #define _CRT_SECURE_NO_WARNINGS
 5 #define HOME
 6
 7 #include <iostream>
 8 #include <cstdlib>
 9 #include <cstdio>
10 #include <cstddef>
11 #include <iterator>
12 #include <algorithm>
13 #include <string>
14 #include <locale>
15 #include <cmath>
16 #include <vector>
17 #include <cstring>
18 using namespace std;
19 const int INF = 0x3f3f3f3f;
20 const int MaxN = 210;
21 const int MaxK = 10;
22
23
24 int N, K;
25 string numStr;
26 int dp[MaxN][MaxK] = { 0 };
27
28 void Solve()
29 {
30     for (int i = 1; i <= N; ++i)
31     {
32         // 划分从2开始,因为dp[][1]已经初始化过了,否则值会被0覆盖掉。
33         for (int j = 2; j <= K; ++j)
34         {
35             if (i < j) break;
36             dp[i][j] = dp[i - 1][j - 1] + dp[i - j][j];
37         }
38     }
39     cout << dp[N][K] << endl;
40 }
41
42 int main()
43 {
44 #ifdef HOME
45     freopen("in", "r", stdin);
46     //freopen("out", "w", stdout);
47 #endif
48
49     cin >> N >> K;
50     for (int i = 1; i <= N; ++i)
51     {
52         dp[i][1] = 1;
53     }
54     Solve();
55
56 #ifdef HOME
57     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
58     _CrtDumpMemoryLeaks();
59     system("pause");
60 #endif
61     return 0;
62 }

 
时间: 2024-10-12 16:46:46

划分型动态规划 之 CODE[VS] 1039 数的划分 2001年NOIP全国联赛提高组的相关文章

划分型动态规划 之 CODE[VS] 1040 统计单词个数 2001年NOIP全国联赛提高组

/* dp[i][k] := 前i+1个字符组成的字符串,划分为k份,每份中包含的单词个数加起来总数的最大值. 初始化: dp[][] = -0x3f3f3f3f   // 注意:对于dp[i][k],若(i+1)<k,则dp[i][k]的值不存在,设为-0x3f3f3f3f.例如:dp[0][2] = -0x3f3f3f3f  dp[i][1] = val[0][i]   //注:val[i][j] := 截取原字符串[从i到j的字符(包含i和j位置的字符)]组成字符串,返回其包含的单词个数

【动态规划】【记忆化搜索】CODEVS 1011 数的计算 2001年NOIP全国联赛普及组

设答案为f(n),我们显然可以暴力地递归求解: f(n)=f(1)+f(2)+……+f(n/2). 但是n=1000,显然会超时. 考虑状态最多可能会有n种,经过大量的重复计算,所以可以记忆下来,减少不必要的计算. 1 #include<cstdio> 2 using namespace std; 3 int n; 4 long long memory[1001]; 5 long long f(int cur) 6 { 7 if(memory[cur]) return memory[cur];

贪心 + 并查集 之 CODE[VS] 1069 关押罪犯 2010年NOIP全国联赛提高组

/* 贪心 + 并查集 之 CODE[VS] 1069 关押罪犯  2010年NOIP全国联赛提高组 两座监狱,M组罪犯冲突,目标:第一个冲突事件的影响力最小. 依据冲突大小,将M组罪犯按从大到小排序,按照排序结果,依次把每组罪犯分开放入两个监狱, 直到当前这组罪犯已经在同一个监狱中了,此时即为答案. 实现: 1)通过不在同一个监狱的罪犯,推断出在同一个监狱的罪犯.(依据:一共就两个监狱)      ftr[b] = a+n   // a和b是在不同监狱 ftr[c] = a+n   // a和

棋盘型动态规划 之 CODE[VS] 1169 传纸条 2008年NOIP全国联赛提高组

/* 这道题要解决两个问题 1)状态和状态方程 2)怎么保证每走一步,所形成的路径不相交,以保证最后生成的完整路径不相交. (1)状态: dp[i][j][k][l] = 小渊传递的纸条到[i][j]的位置,小轩传递的纸条到[k][l]的位置时,好心程度和的最大值. (2)状态方程: 看到题目,直接的想法是: 按题意,小渊从左上角->右下角,小轩从右下角->左上角.但是,路径在走的时候,怎么才能保证路径不相交,我想不出来办法了... 仔细想,题目要求: 两条路径的头尾坐标相同(出发点选择不同)

划分DP:乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提高组

乘积最大   题目描述  Description 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加.活动中,主持人给所有参加活动的选手出了这样一道题目: 设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大. 同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子: 有一个数字串

CODE[VS] 1098 均分纸牌 ( 2002年NOIP全国联赛提高组)

arr[i] :表示每个牌堆的纸牌的数目 平均值 :当纸牌数都一样多时,纸牌的数目 从左向右考虑,每堆纸牌有三种状态: 1) arr[i] == 平均值,考虑arr[i+1] 2) arr[i] < 平均值,此时由arr[i+1]移给arr[i]纸牌. => 移动纸牌数:(平均值 - arr[i])张    注:   考虑此时,arr[i]缺牌,那么i右边的牌堆必然多牌,无论哪堆多牌,必然有由arr[i+1]将牌移给arr[i]的过程. 3) arr[i] > 平均值,此时由arr[i]

【基础练习】【卡特兰数】栈 2003年NOIP全国联赛普及组第三题 题解

卡特兰数,这是一向掌握不大熟练的内容,今天借NOIP2003普及组的第三题来总结一下.当然由于原题数据弱抱,不需要高精.如果有时间我会不断补充这篇文章里的内容. 二话不说上代码 //Catalan #include<iostream> using namespace std; long long n,f[20]={0}; /*NO.1 f[n+1]=f[i]*f[n-i]from 0 to n plus f[0]=1 int main(){ cin>>n; f[0]=1;f[1]=

【动态规划】【零一背包】CODEVS 1014 装箱问题 2001年NOIP全国联赛普及组

1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int n,m,w[31],f[30001]; 5 int main() 6 { 7 scanf("%d%d",&m,&n); 8 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 9 for(int i=1;i<=n;i++) 10 for(i

洛谷 P1980 记数问题 2013年NOIP全国联赛普及组

3291 记数问题 2013年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解题目描述 Description试计算在区间1到n的所有整数中,数字x(0≤x≤9)共出现了多少次?例如,在1到11中,即在1.2.3.4.5.6.7.8.9.10.11中,数字1出现了4次. 输入描述 Input Description输入共1行,包含2个整数n.x,之间用一个空格隔开. 输出描述 Output Description输出共1行,包含一个整