alice132

 

2026.1.17 作业 - P4141 消失之物

题目描述

ftiasch 有 \(n\) 个物品, 体积分别是 \(w_1,w_2,\dots,w_n\)。由于她的疏忽,第 \(i\) 个物品丢失了。

“要使用剩下的 \(n-1\) 物品装满容积为 \(x\) 的背包,有几种方法呢?”——这是经典的问题了。

她把答案记为 \(\text{cnt}(i,x)\) ,想要得到所有\(i \in [1,n]\), \(x \in [1,m]\)\(\text{cnt}(i,x)\) 表格。

输入格式

第一行两个整数 \(n,m\),表示物品的数量和最大的容积。
第二行 \(n\) 个整数 \(w_1,w_2,\dots,w_n\),表示每个物品的体积。

输出格式

输出一个 \(n \times m\) 的矩阵,表示 \(\text{cnt}(i,x)\)末位数字

输入输出样例 #1

输入 #1

3 2
1 1 2

输出 #1

11
11
21

说明/提示

【数据范围】
对于 \(100\%\) 的数据,\(1\le n,m \le 2000\),且 \(1\le w_i\le 2000\)

【样例解释】
如果物品 3 丢失的话,只有一种方法装满容量是 2 的背包,即选择物品 1 和物品 2。

题解

思考1: 在没有丢失的情况下:
$F[n][j]=F[n-1][j]+F[n-1][j-w[i]] $
$F[n][j] $ 表示前 \(n\) 个物品,装满空间 \(j\)的方案数。
$F[n-1][j] $ 表示前 \(n-1\) 个物品, 装满空间 \(j\)的方案数。 等价于:删除第n个物品时的方案数
$F[n-1][j] $ 表示前 \(n-1\) 个物品,装满空间 $j-w[i] $的方案数,等价于:一定包含第 \(n\) 个物品,装满空间 \(j\) 的方案数

思考2: 已经 \(n\) 个物品装满空间 \(j\) 的方案数,求 删除第 \(n\) 个物品装满空间 \(j\) 的方案数 \(cnt[n][j]\)

$ cnt[n][j] : F[n-1][j]=F[n][j]-F[n-1][j-w[i]] , j>=w[i] $

$ cnt[n][j]: F[n-1][j]= F[n][j] , j<w[i]$

思考3: 如何删除 物品 \(1\) --物品 \(n-1\)
求背包类dp问题中,物品的顺序,不影响方案数。任意一个物品都可以当成第 \(n\) 个物品来思考。

#include <iostream>
using namespace std;
int n,m,w[2002],cnt[2002][2002],F[2002];
int main() {
    cin>>n>>m;
    for (int i=1;i<=n;i++) cin>>w[i];
    F[0]=1;
    for (int i=1;i<=n;i++)
        for (int j=m;j>=w[i];j--) F[j]=(F[j]+F[j-w[i]])%10;
    for (int i=1;i<=n;i++) {
        for (int j=0;j<w[i];j++) cnt[i][j]=F[j];
        for (int j=w[i];j<=m;j++) cnt[i][j]=(F[j]-cnt[i][j-w[i]]+10)%10;
    }
    for (int i=1;i<=n;i++) {
        for (int j=1;j<=m;j++) cout<<cnt[i][j]%10;
        cout<<endl;
    }
    return 0;
}

posted on 2026-01-19 20:43  alice_ss  阅读(1)  评论(0)    收藏  举报

导航