『旋转体积背包』sop

这篇博客探讨了如何运用动态规划解决一类允许元素重复的背包问题,通过递推公式`fi,j=fi−1,j−1+fi−j,j`进行状态转移,并详细解释了如何计算某个数字出现特定次数的方案数,最后展示了相关的代码实现。" 48574493,5388401,NetBeans GUI编程教程,"['Java开发', 'GUI设计', 'NetBeans IDE']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem\mathrm{Problem}Problem

在这里插入图片描述


Solution\mathrm{Solution}Solution

前置芝士:求解 ∑ai=N\sum a_i=Nai=N 的方案数

我们考虑DP,设 fi,jf_{i,j}fi,j 表示和为 iii ,数字个数为 jjj 的方案数。

我们需要让它你能重复,因此我们的转移必须从小到大或从大到小来转移。

我们考虑从大到小转移,那么若当前的最小数字不是1,我们可以考虑每一个数字都减1,对应的方案数是 fi−j,jf_{i-j,j}fij,j ,否则方案数是 fi−1,j−1f_{i-1,j-1}fi1,j1,因此就有递推式为:fi,j=fi−1,j−1+fi−j,jf_{i,j}=f_{i-1,j-1}+f_{i-j,j}fi,j=fi1,j1+fij,j

考虑一个数 xxx 在某一个方案里面出现了 iii 次的方案数,设方案数为 ttt,那么当前的贡献则为xm⋅t⋅ix^m·t·ixmti。考虑如何利用上面的数组。

  • 出现了至少 iii 次的方案数为 fn−xi,k−if_{n-xi,k-i}fnxi,ki.
  • 则出现了刚好 iii 次的方案数为 fn−xi,k−i−fn−xi−x,k−i−1f_{n-xi,k-i}-f_{n-xi-x,k-i-1}fnxi,kifnxix,ki1,差分即可。

Code\mathrm{Code}Code

#include <bits/stdc++.h>

using namespace std;
const int P = 998244353;

int n, m, k, res;
int Now[100], Val[100];

inline void Dfs(int x, int sum, int val, int last)
{
	if (x == k + 1) 
	{
		if (sum < n) return;
		res = (res + val) % P;
		return;
	}
	for (register int i=last;i<=n;++i)
		if (sum + i <= n) Now[x] = i, Dfs(x+1, (sum + i) % P, (val + Val[i]) % P, i);
	return; 
}

inline int power(int a, int b) {
	int res = 1;
	while (b > 0) {
		if (b & 1) res = 1LL * res * a % P;
		a = 1LL * a * a % P, b >>= 1;
	}
	return res;
}
 
int main(void)
{
	freopen("sop.in","r",stdin);
	freopen("sop.out","w",stdout);
	cin >> n >> k >> m;
	for (register int i=1;i<=n;++i) Val[i] = power(i, m);
	Dfs(1, 0, 0, 1);
	cout << res << endl;
	return 0;
} 
背包问题是一个经典的动态规划问题,其中背包有一定的容量,物品有不同的体积和价值。目标是在不超过背包容量的情况下,使得放入背包的物品总价值最大化。 下面是一个用C++实现的带体积背包问题的代码示例: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int knapsack(int capacity, vector<int>& volumes, vector<int>& values, int n) { // 创建一个二维数组来保存动态规划的结果 vector<vector<int>> dp(n+1, vector<int>(capacity+1, 0)); for (int i = 1; i <= n; i++) { for (int j = 1; j <= capacity; j++) { if (volumes[i-1] <= j) { // 当前物品的体积小于等于背包容量时,可以选择放入或不放入背包 dp[i][j] = max(values[i-1] + dp[i-1][j-volumes[i-1]], dp[i-1][j]); } else { // 当前物品的体积大于背包容量时,只能选择不放入背包 dp[i][j] = dp[i-1][j]; } } } return dp[n][capacity]; } int main() { int capacity = 10; // 背包容量 vector<int> volumes = {2, 3, 4, 5}; // 物品的体积 vector<int> values = {3, 4, 5, 6}; // 物品的价值 int n = volumes.size(); // 物品的数量 int maxValue = knapsack(capacity, volumes, values, n); cout << "最大价值为: " << maxValue << endl; return 0; } ``` 这段代码使用动态规划的思想,通过填充一个二维数组 `dp` 来解决背包问题。其中 `dp[i][j]` 表示在前 `i` 个物品中,背包容量为 `j` 的情况下,可以获得的最大价值。最终返回 `dp[n][capacity]` 即可得到结果。 注意,这段代码假设物品的体积和价值已经按照相同的顺序存储在 `volumes` 和 `values` 向量中,并且索引从0开始。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值