2017成都聯訓Day2,身心疲憊~
據 dsfz JCY (%%% Orz) 大神說,此題可以用線段樹分治解決,但我調了一晚上沒調出來…(我太垃圾了…)
bzoj 2287 消失之物
Description
ftiasch 有 N 個物品, 體積分別是
W1,W2,…,WN 。 由於她的疏忽, 第 i 個物品丟失了。 “要使用剩下的 N – 1 物品裝滿容積爲 x 的揹包,有幾種方法呢?” — 這是經典的問題了。她把答案記爲Counti,x ,想要得到所有1≤i≤N,1≤x≤M 的Counti,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。令
用若干個物品填充0的體積,方案書只有一種,就是什麼也不選;用前i個物品填充j的體積,當第i個物品的體積大於j時,i無論如何也不可能被使用,所以問題就等價於用前i-1個物品去填充j的體積。當
再考慮
這樣的話我們就可以遞推了,時間複雜度
(不靠譜的)代碼
我沒有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;
}