-------------------------------------------
链接:P4141 消失之物
--------------------------------------------------
这道题确实很坑,在上课的时候,我们老师讲了一个分治的做法。
然而分治实在太玄学了。但是老师的课件上面还写了“有一种更简单的操作,但是没有拓展性。”
这种做法是什么呢?
非常简单,比如说我们要求出在没有i物品时的x的方案,我们只要先跑一边背包得到在所有物品都有的情况下的方案总数,然后把由i物品得到的方案数(贡献)减掉就行了
很简单吧(所以说没拓展性)
--------------------------------------------------
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int f[10000];//第一遍背包的数组 7 int n; 8 int v[10000]; 9 int g[10000];//因为我们会经常更新, 10 //所以需要一个额外数组 11 int m; 12 13 int main(){ 14 cin>>n>>m; 15 for(int i=1;i<=n;++i){ 16 cin>>v[i]; 17 } 18 g[0]=f[0]=1; 19 for(int i=1;i<=n;++i) 20 for(int j=m;j>=0;--j){ 21 if(j>=v[i]) 22 { 23 f[j]+=f[j-v[i]]; 24 f[j]%=10; 25 } 26 } 27 28 //标准的01背包求方案数 29 for(int i=1;i<=n;++i)//枚举失去每一个物品 30 { 31 memcpy(g,f,sizeof(f));//一定不能操作原数组 32 for(int j=1;j<=m;++j){//枚举失去后的每一种可能的要求容量 33 if(j>=v[i]){ 34 g[j]-=g[j-v[i]];//减去由i得到的部分 35 g[j]+=10;//有可能是负数 36 g[j]%=10; 37 } 38 else 39 g[j]=f[j]%10; 40 cout<<g[j]; 41 } 42 cout<<endl; 43 } 44 return 0; 45 }