【BZOJ2287】消失之物 [分治][DP]

消失之物

Time Limit: 10 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

Description

  ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN

  由于她的疏忽, 第 i 个物品丢失了.

  “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢?” -- 这是经典的问题了。

  她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。

Input

  第1行:两个整数 NM ,物品的数量和最大的容积。
  第2行: N 个整数 W1, W2, ..., WN, 物品的体积。

Output

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

Sample Input

  3 2
  1 1 2

Sample Output

  11
  11
  21

HINT

  1 ≤ N ≤ 2 × 1e3, 1 ≤ M ≤ 2 × 1e3

Solution

  首先,我们发现,对于L,R:
  去掉L,就是要用[1, L - 1]∪[L + 1, n]的物品来求解;
  去掉R,就是要用[1, R - 1]∪[R + 1, n]的物品来求解。
  若是我们更新完了([1, L - 1]∪[L + 1, n])([1, R - 1]∪[R + 1, n])的部分,
  再加上L的,即是去掉R的答案;再加上R的,即是去掉L的答案。

  那么我们就可以考虑分治
  设计状态Solve(L, R),表示已经做完了[1, L - 1]∪[R + 1, n]时的答案。
  然后二分一个mid = L + R >> 1;
  要处理[L, mid]则将[mid + 1, R]的更新一下,反之同理。
  那么这样我们最后做到L == R时候,显然就是去掉L的答案了。

  DP部分显然就是一个简单的背包。

Code

 

 1 #include<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cmath>
 8 #include<queue>
 9 using namespace std;
10 typedef long long s64;
11 
12 const int ONE = 100005;
13 const int INF = 2147483640;
14 
15 int n, m;
16 int a[ONE];
17 int f[20][ONE];
18 
19 int get()
20 {
21         int res=1,Q=1;  char c;
22         while( (c=getchar())<48 || c>57)
23         if(c=='-')Q=-1;
24         if(Q) res=c-48; 
25         while((c=getchar())>=48 && c<=57) 
26         res=res*10+c-48;
27         return res*Q; 
28 }
29 
30 void Solve(int L, int R, int Dep)
31 {
32         if(L == R)
33         {
34             for(int j = 1; j <= m; j++)
35                 printf("%d", f[Dep][j]);
36             printf("\n");
37             return;
38         }
39 
40         int mid = L + R >> 1;
41 
42         for(int j = m; j >= 0; j--) f[Dep + 1][j] = f[Dep][j];
43         for(int i = mid + 1; i <= R; i++)
44             for(int j = m; j >= 0; j--)
45                 (f[Dep + 1][j] += f[Dep + 1][j - a[i]]) %= 10;
46         Solve(L, mid, Dep + 1);
47 
48         for(int j = m; j >= 0; j--) f[Dep + 1][j] = f[Dep][j];
49         for(int i = L; i <= mid; i++)
50             for(int j = m; j >= 0; j--)
51                 (f[Dep + 1][j] += f[Dep + 1][j - a[i]]) %= 10;
52         Solve(mid + 1, R, Dep + 1);
53 }
54 
55 int main()
56 {
57         n = get();    m = get();
58         for(int i = 1; i <= n; i++) a[i] = get();
59         f[0][0] = 1;
60         Solve(1, n, 0);
61 }
View Code

 

posted @ 2017-10-24 20:18  BearChild  阅读(291)  评论(0编辑  收藏  举报