bzoj 2287 消失之物

2017成都聯訓Day2,身心疲憊~

據 dsfz JCY (%%% Orz) 大神說,此題可以用線段樹分治解決,但我調了一晚上沒調出來…(我太垃圾了…)

bzoj 2287 消失之物

Description

ftiasch 有 N 個物品, 體積分別是 W1,W2,,WN 。 由於她的疏忽, 第 i 個物品丟失了。 “要使用剩下的 N – 1 物品裝滿容積爲 x 的揹包,有幾種方法呢?” — 這是經典的問題了。她把答案記爲 Counti,x ,想要得到所有1iN,1xMCounti,x 表格。

原題配圖

Input

第1行:兩個整數 N (1 ≤ N ≤ 2 × 103) 和 M (1 ≤ M ≤ 2 × 103),物品的數量和最大的容積。

第2行: N 個整數 W1, W2, …, WN, 物品的體積。

Output

一個 N × M 的矩陣, Count(i, x)的末位數字。

Sample Input

3 2
1 1 2

Sample Output

11
11
21

Hint

如果物品3丟失的話,只有一種方法裝滿容量是2的揹包,即選擇物品1和物品2。

來自黃學長的解題思路

首先,先考慮一個普普通通的揹包DP。令Fi,j 表示用前i 個物品填滿一個體積爲j 的揹包的方案數,那麼就有:

Fi,j=1: j=0Fi1,j:j>wiFi1,j+Fi1,jwi:0<jwi

用若干個物品填充0的體積,方案書只有一種,就是什麼也不選;用前i個物品填充j的體積,當第i個物品的體積大於j時,i無論如何也不可能被使用,所以問題就等價於用前i-1個物品去填充j的體積。當0<jwi 時,第i個物品要麼用要麼不用:如果用就要用剩下的i-1個物品填充其餘的jwi 的體積;如果第i個物品不用,那麼問題就等價於用前i-1個物品填充j的體積(再根據加法原理,可得該式)。

再考慮Counti,j :使用除了物品i之外的n-1個物品,填充j的體積的方案數。

Counti,j=fn,j:0<j<wi :當物品i的體積大於j時,i本來就不可能被用到,自然與fn,j 相等。

Counti,j=fn,jCounti,jwi:jwi :在這種情況下物品i會被使用,不用物品i填充j的體積的方案數就等於用所有物品填充體積j的方案數再減去其中使用了物品i的方案數。強制使用使用物品i填充j的體積,就相當於禁止使用物品i填充了jwi 的體積,(因爲i佔據了j中wi 的體積)。

這樣的話我們就可以遞推了,時間複雜度O(n2)

(不靠譜的)代碼

我沒有BZOJ權限號,此代碼未經過任何測試(除了過了樣例)。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=2000+10;
int w[maxn],f[maxn],c[maxn][maxn];
int main(){
    int n,m;scanf("%d%d",&n,&m);f[0]=1;
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    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++){
        c[i][0]=1;
        for(int j=1;j<=m;j++){
            if(j-w[i]>=0){
                c[i][j]=(f[j]-c[i][j-w[i]]+10)%10;
            }else c[i][j]=f[j];
            printf("%d",c[i][j]);
        }
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章