首页 > 其他 > 详细

消失之物,分治

时间:2019-07-30 20:09:32      阅读:91      评论:0      收藏:0      [点我收藏+]

ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN。 由于她的疏忽, 第 i 个物品丢失了。 “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢?” -- 这是经典的问题了。她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。

技术分享图片View Code

输入格式

第1行:两个整数 N (1 ≤ N ≤ 2 × 103) 和 M (1 ≤ M ≤ 2 × 103),物品的数量和最大的容积。

第2行: N 个整数 W1, W2, ..., WN, 物品的体积。

输出格式

一个 N × M 的矩阵, Count(i, x)的末位数字

 

样例

样例输入

3 2
1 1 2

样例输出

11
11
21

。。。我也不知道我是怎么想到的,只记得一开始我打了个O(n2mlogn)的代码交上后比暴力还慢。。。。

由此想到:合并背包的复杂度为n2,所以与其合并背包还不如一个一个地添加元素,由此可以想到:我们

考虑每个物品对复杂度的贡献,期望为mlogn,那么是不是可以用分治?so:假如我们有一棵线段树,在

线段树的每一层对每一个物品跑背包,保证每个物品的贡献,so:我们还是考虑线段树:在线段树的

每一个结点开一个背包,怎么用呢?考虑每个物品对答案的贡献,对线段树的没个非叶子节点:

假设某个节点控制范围为l到r,则mid=l+r>>1;(废话)那么(l,mid)范围内所有的点会对(mid+1,r)

的答案作出贡献,所以把(l,mid)内每个物品单独取出,加入到rc的背包中,并且在考虑以rc为根的子树时

把rc的背包下传以传递贡献,下传时直接memcpy即可;在叶子节点统计答案,直接输出

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define N 2003
 3 #define reg register
 4 using namespace std;
 5 int n, m;
 6 int w[N];
 7 int pos[N];
 8 int f[N << 2][N];
 9 void ask(const int g, const int l, const int r) {
10     if (l == r) {
11         pos[l] = g;
12         return;
13     }
14     const int mid = l + r >> 1, lc = g << 1, rc = g << 1 | 1;
15     f[lc][0] = f[rc][0] = 1;
16     for (int i = 1; i <= m; ++i) f[lc][i] = f[rc][i] = f[g][i];
17     for (reg int i = mid + 1; i <= r; ++i) {
18         for (reg int j = m; j >= w[i]; --j) {
19             f[lc][j] += f[lc][j - w[i]];
20             f[lc][j] = f[lc][j] >= 10 ? f[lc][j] - 10 : f[lc][j];
21         }
22     }
23     for (reg int i = l; i <= mid; ++i) {
24         for (reg int j = m; j >= w[i]; --j) {
25             f[rc][j] += f[rc][j - w[i]];
26             f[rc][j] = f[rc][j] >= 10 ? f[rc][j] - 10 : f[rc][j];
27         }
28     }
29     ask(lc, l, mid);
30     ask(rc, mid + 1, r);
31 }
32 int main() {
33     scanf("%d%d", &n, &m);
34     for (reg int i = 1; i <= n; ++i) scanf("%d", &w[i]);
35     ask(1, 1, n);
36     for (reg int i = 1; i <= n; ++i) {
37         for (reg int j = 1; j <= m; ++j) putchar(f[pos[i]][j] + 48);
38         puts("");
39     }
40 }
感谢loj码风优化(貌似某位压行大神也写过?)

优化:

1.其实不必在所有节点开背包,在每层开一个即可;

2.到达叶子节点可直接输出答案,不必最后统计输出;

 

 

 

消失之物,分治

原文:https://www.cnblogs.com/loadingkkk/p/11272338.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!