消失之物

Time Limit: 10 Sec Memory Limit: 128 MB

Description

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

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

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

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

img

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
using namespace std;
typedef long long s64;

const int ONE = 100005;
const int INF = 2147483640;

int n, m;
int a[ONE];
int f[20][ONE];

int get()
{
int res=1,Q=1; char c;
while( (c=getchar())<48 || c>57)
if(c=='-')Q=-1;
if(Q) res=c-48;
while((c=getchar())>=48 && c<=57)
res=res*10+c-48;
return res*Q;
}

void Solve(int L, int R, int Dep)
{
if(L == R)
{
for(int j = 1; j <= m; j++)
printf("%d", f[Dep][j]);
printf("\n");
return;
}

int mid = L + R >> 1;

for(int j = m; j >= 0; j--) f[Dep + 1][j] = f[Dep][j];
for(int i = mid + 1; i <= R; i++)
for(int j = m; j >= 0; j--)
(f[Dep + 1][j] += f[Dep + 1][j - a[i]]) %= 10;
Solve(L, mid, Dep + 1);

for(int j = m; j >= 0; j--) f[Dep + 1][j] = f[Dep][j];
for(int i = L; i <= mid; i++)
for(int j = m; j >= 0; j--)
(f[Dep + 1][j] += f[Dep + 1][j - a[i]]) %= 10;
Solve(mid + 1, R, Dep + 1);
}

int main()
{
n = get(); m = get();
for(int i = 1; i <= n; i++) a[i] = get();
f[0][0] = 1;
Solve(1, n, 0);
}