[关闭]
@ysner 2018-09-18T14:33:19.000000Z 字数 1470 阅读 2076

[loj6089]小Y的背包计数问题

DP


题面

有一个大小为的背包,并且小种物品。
对于第种物品,共有个可以使用,并且对于每一个物品,体积均为
求小把该背包装满的方案数为多少,答案对于取模。
定义两种不同的方案为:当且仅当至少存在一种物品的使用数量不同。

解析

这个背包问题让我耳目一新啊。
棒棒的。

注意到题目中物品)的个数限制实际上是不存在的。
所以可以把这个问题分为两个子问题:多重背包问题和完全背包问题。

表示前个物品,总体积为时的方案数。
对于:(多重背包问题)
很显然有


可以前缀和优化做到

对于:(完全背包问题)
又注意到一个物品最多取个。
同样设个表示方案数。
可以认为我们要出一个和为,最小数至少的不下降序列
(序列中的数是物品体积)。
转移有两种:


这个复杂度
最后讨论一下给前一个问题分配多少体积,后一个问题分配多少体积,统计答案即可。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define max(a,b) (((a)>(b))?(a):(b))
  11. #define min(a,b) (((a)<(b))?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=2005,inf=2e9,mod=23333333;
  16. int n,f[N],g[350][N],s[N],ans=-inf,m;
  17. il ll gi()
  18. {
  19. re ll x=0,t=1;
  20. re char ch=getchar();
  21. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  22. if(ch=='-') t=-1,ch=getchar();
  23. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  24. return x*t;
  25. }
  26. int main()
  27. {
  28. n=gi();m=sqrt(n);
  29. f[0]=1;
  30. fp(i,1,m)
  31. {
  32. fp(j,0,i) s[j]=f[j];
  33. fp(j,i,n) s[j]=(f[j]+s[j-i])%mod;//前缀和
  34. fp(j,0,n)
  35. {
  36. f[j]=s[j];
  37. if(j-i*(i+1)>=0) f[j]=(f[j]-s[j-i*(i+1)]+mod)%mod;//去掉不合法状态
  38. }
  39. }
  40. g[0][0]=1;ans=f[n];
  41. fp(i,1,m)
  42. for(re int j=i*(m+1);j<=n;j++)
  43. {
  44. g[i][j]=(g[i-1][j-m-1]+g[i][j-i])%mod;
  45. (ans+=1ll*g[i][j]*f[n-j]%mod)%=mod;
  46. }
  47. printf("%d\n",ans);
  48. return 0;
  49. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注