(经典)POJ-3181 完全背包+大数处理

题目大意:给定N,K,用1-K组成N,一共有多少组合方法?


题目链接:点击打开链接


分析:

这题属于完全部分和问题,其实也可以理解为划分数问题。如n为3,k为2时,有

1+2

1+1+1  这2种方法,我们可以理解为用1和2去填满或者组成3,这样想便是完全背包可行性也就是完全部分和问题。

或者这样看,

1|11

1|1|1  这样的话便是一个划分数问题,即将n个1划分组且每组最多k个的问题,利用逆向思想,我们常常将划分数问题转化为完全部分和问题来求解(即划分与组合是个可逆的过程)。

状态:dp[i][j]前i种物品(1-i价格)花费j元的种数

决策:第i种不买或者至少买一个

转移:

不买的话显然为dp[i-1][j]

至少买一个的话为dp[i][j-i](注意与多重问题的区别,想一想为什么)

所以 dp[i][j] = dp[i-1][j] + dp[i][j-i],最终提交还是错了,自己输出一些数据测试发现出现了不正常的数说明很有可能溢出了,可是如果写一个高精度的话肯定是要TLE的。在网上看到一种很巧妙的方法,由于最大结果也只有33位(别人说的。。),long long可以存储19位,所以可以利用2个long long来存一个33位+的数,具体实现也很简单,直接看代码吧。


附上代码:

#include<iostream>
using namespace std;
int n, k;
long long MOD = 1;
long long dp1[1005], dp2[1005];
int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 0; i < 18; i++)
		MOD *= 10;
	dp2[0] = 1;
	for (int i = 1; i <= k; i++)
		for (int j = 0; j <= n; j++)
		{
			if (j - i >= 0)
			{
				dp1[j] = dp1[j] + dp1[j - i] + (dp2[j] + dp2[j - i]) / MOD;  //算出i,j对应的高位
				dp2[j] = (dp2[j] + dp2[j - i]) % MOD;           //算出低位
			}
			else
			{
				dp1[j] = dp1[j];
				dp2[j] = dp2[j];
			}
		}
	if (dp1[n]) printf("%lld", dp1[n]);
	printf("%lld\n", dp2[n]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值