bzoj2287 POJ Challenge 消失之物(背包)
2287: 【POJ Challenge】消失之物
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 735 Solved: 413
[Submit][Status][Discuss]
Description
ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN。 由于她的疏忽, 第 i 个物品丢失了。 “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢?” -- 这是经典的问题了。她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。
Input
第1行:两个整数 N (1 ≤ N ≤ 2 × 103) 和 M (1 ≤ M ≤ 2 × 103),物品的数量和最大的容积。
第2行: N 个整数 W1, W2, ..., WN, 物品的体积。
Output
一个 N × M 的矩阵, Count(i, x)的末位数字。
第一反应是跑前缀背包和后缀背包,但是发现是$n^3$的orz;
实际计算count数组时可以用FFT优化,复杂度$O(n^2·logn)$;
正解:(来自http://hzwer.com/2446.html)
递推求count时,分三种情况讨论:
1、$count[i][0]=1$;
2、$j<w[i]$时,不会用到第$i$个物品,因此$count[i][j]=dp[n][j]$;
3、$j>=w[i]$时,注意到使用第$i$个物品填满背包等价于不用第$i$个物品填充$m-w[i]$的体积;
因此$count[i][j]=dp[n][j]-count[i][j-w[i]]$;
复杂度$O(n^2)$;
AC GET☆DAZE
↓代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #define ll long long 11 using namespace std; 12 int dp[2039][2039],wei[2039],con[2039][2039]; 13 int main() 14 { 15 int n,m,a,b,c; 16 scanf("%d%d",&n,&m); 17 for(a=1;a<=n;a++) 18 { 19 scanf("%d",&wei[a]); 20 } 21 dp[0][0]=1; 22 for(a=1;a<=n;a++) 23 { 24 for(b=0;b<=m;b++) 25 { 26 if(b>=wei[a]) 27 { 28 dp[a][b]+=dp[a-1][b-wei[a]]; 29 } 30 dp[a][b]+=dp[a-1][b]; 31 dp[a][b]%=10; 32 } 33 } 34 for(a=1;a<=n;a++) 35 { 36 con[a][0]=1; 37 for(b=1;b<wei[a];b++) 38 { 39 con[a][b]=dp[n][b]; 40 } 41 while(b<=m) 42 { 43 con[a][b]=(dp[n][b]-con[a][b-wei[a]]+10)%10; 44 b++; 45 } 46 } 47 for(a=1;a<=n;a++) 48 { 49 for(b=1;b<=m;b++) 50 { 51 printf("%d",con[a][b]); 52 } 53 cout<<endl; 54 } 55 return 0; 56 }