经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C » 查看文章
51nod 1597 有限背包计数问题 (背包 分块)
来源:cnblogs  作者:自为风月马前卒  时间:2018/10/19 9:20:01  对本文有异议

题意

题目链接

Sol

不会做啊AAA。。

暴力上肯定是不行的,考虑根号分组

\(m = \sqrt{n}\)

对于前\(m\)个直接暴力,利用单调队列优化多重背包的思想,按\(\% i\)分组一下。复杂度\(O(n\sqrt{n})\)

对于后\(m\)个,此时每个物品没有个数的限制,换一种dp方法

\(g[i][j]\)表示用了\(i\)物品,大小为\(j\)的方案数。

转移的时候有两种方案

  1. 把当前所有物品大小\(+1\)\(g[i][j + i] += g[i][j]\)

  2. 新加入一个最小的物品, \(g[i + 1][j + m + 1] += g[i][j]\)

看上去很显然,但自己想不出来qwq

  1. #include<cstdio>
  2. #include<cmath>
  3. #include<cstring>
  4. #define pt(x) printf("%d\n", x);
  5. using namespace std;
  6. const int MAXN = 1e5 + 10, mod = 23333333;
  7. int N, M, f[81][MAXN], g[81][MAXN];
  8. int add(int x, int y) {
  9. return (x + y >= mod) ? (x + y - mod): x + y;
  10. }
  11. int main() {
  12. scanf("%d", &N);
  13. M = sqrt(N);
  14. /*f[0][0] = 1; int o = 1;
  15. for(int i = 1; i <= M; i++) {
  16. for(int k = 0; k < i; k++) {//res
  17. int s = 0;
  18. for(int t = 0; i * t + k <= N; t++) {//num
  19. s = add(s, f[i - 1][k + t * i]);
  20. f[i][k + t * i] = s;
  21. if(t >= i) s = (s - f[i - 1][(t - i) * i + k] + mod) % mod;//over take
  22. }
  23. }
  24. }
  25. int ans = f[M][N];
  26. pt(ans)
  27. g[0][0] = 1; int p = 0;
  28. for(int i = 1; i <= M; i++) {// used i goods
  29. for(int j = 0; j <= N; j++) {// length is j
  30. if(j >= M + 1) g[i][j] = g[i - 1][j - (M + 1)];
  31. if(j >= i) g[i][j] = add(g[i][j], g[i][j - i]);
  32. }
  33. for(int j = 0; j <= N; j++) (ans += 1ll * f[M][j] * g[i][N - j] % mod) %= mod;
  34. }
  35. printf("%d", ans);*/
  36. f[0][0] = 1; int o = 1;
  37. for(int i = 1; i <= M; i++, o ^= 1) {
  38. memset(f[o], 0, sizeof(f[o]));
  39. for(int k = 0; k < i; k++) {//res
  40. int s = 0;
  41. for(int t = 0; i * t + k <= N; t++) {//num
  42. s = add(s, f[o ^ 1][k + t * i]);
  43. f[o][k + t * i] = s;
  44. if(t >= i) s = (s - f[o ^ 1][(t - i) * i + k] + mod) % mod;//over take
  45. }
  46. }
  47. }
  48. int ans = f[o ^ 1][N], tmp = o ^ 1;
  49. pt(ans)
  50. g[0][0] = 1; o = 1;
  51. for(int i = 1; i <= M; i++, o ^= 1) {// used i goods
  52. memset(g[o], 0, sizeof(g[o]));
  53. for(int j = 0; j <= N; j++) {// length is j
  54. if(j >= M + 1) g[o][j] = g[o ^ 1][j - (M + 1)];
  55. if(j >= i) g[o][j] = add(g[o][j], g[o][j - i]);
  56. }
  57. for(int j = 0; j <= N; j++) (ans += 1ll * f[tmp][j] * g[o][N - j] % mod) %= mod;
  58. }
  59. printf("%d", ans);
  60. return 0;
  61. }
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号