【回退背包】AT2346 [ARC070B] No Need

· · 个人记录

https://www.luogu.com.cn/problem/AT2346

刚开始没注意k<=5000,死想想不出,结果瞄了一眼题解...

那不直接把大于k的a全部删了不就行了? ~~气死偶列~~ 警示后人 然后赶紧返回来想,结果发现其实是个很简单的技巧。也就是回退背包。 我们可以考虑先全局做一个背包,然后考虑每一个物品消失后对答案的影响。 这也就是说,假设当前价值为val,$f[i]-=f[i-val]$(注意要正过来做) 然后找一遍可能转移到大于k的f就做完了 本题不难,只是想总结有这么一个叫回退背包的东西 代码(B题都挂了没救了没救了): ```cpp #include<bits/stdc++.h> #define LL long long using namespace std; LL n,k,N,ans,a[5005],b[5005],f[5005]; int main() { cin>>n>>k; for(int i=1;i<=n;i++){ cin>>a[i]; if(a[i]<=k)b[++N]=a[i]; } f[0]=1; for(int i=1;i<=N;i++){ for(int j=k;j>=b[i];j--){ f[j]+=f[j-b[i]]; } } for(int i=1;i<=N;i++){ for(int j=b[i];j<=k;j++){ f[j]-=f[j-b[i]]; } bool pd=0; for(int j=k-b[i];j<k;j++){ if(f[j]){ pd=1; break; } } if(!pd)ans++; for(int j=k;j>=b[i];j--){ f[j]+=f[j-b[i]]; } } cout<<ans<<endl; return 0; } ```