TIOJ 1475 錄製專輯 (Record)

contents

  1. 1. Problem
  2. 2. Sample Input
  3. 3. Sample Output
  4. 4. Solution

Problem

Jolin 是個愛唱歌的小孩,每次總喜歡邊唱邊用電腦把自己的歌聲錄下來,因此長久下來,在她的電腦裡,已儲存了為數不小的個人歌唱作品。由於耶誕節快要到了,為了準備一份特別的耶誕禮物給爸爸,Jolin 準備從電腦中儲存的個人歌唱作品,挑選幾首歌製成一張個人專輯 CD。由於每張 CD 的容量有限,而Jolin 的個人歌唱作品早已遠遠超過一張 CD 可收錄的容量,因此 Jolin 希望你可以幫她想辦法,讓她所製作的專輯中,能有數目最多的歌曲(請注意:每一首歌只能被收錄一次),同時必需剛好裝滿整張 CD,不留下任何未使用的空間。

Sample Input

1
2
3
4
5
6
5
10 50 30 70 60
80
5
10 50 30 70 60
20

Sample Output

1
2
2 4
0 0

Solution

實作 C++ 簡單的加法、乘法大數,直接把別提的拿過來用。

套用 0/1 背包問題,額外增加大數紀錄方法數,最後乘上 $N!$ 即可。

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <bits/stdc++.h> 
using namespace std;

class BigInteger {
public:
vector<long long> v;
long long MAXC;
BigInteger(int x = 0) {
v = vector<long long>(10, 0);
v[0] = x;
MAXC = 100000000;
normal();
}
BigInteger operator+(const BigInteger &x) const {
BigInteger r(0);
r.v.resize(max(v.size(), x.v.size()) + 2, 0);
for (int i = 0; i < v.size(); i++)
r.v[i] += v[i];
for (int i = 0; i < x.v.size(); i++)
r.v[i] += x.v[i];
r.normal();
return r;
}
BigInteger operator*(const BigInteger &x) const {
BigInteger r(0);
r.v.resize(v.size() + x.v.size() + 2, 0);
for (int i = 0; i < v.size(); i++) {
if (v[i] == 0)
continue;
for (int j = 0; j < x.v.size(); j++)
r.v[i+j] += v[i] * x.v[j];
}
r.normal();
return r;
}
void normal() {
for (int i = 0; i < v.size(); i++) {
if (v[i] >= MAXC) {
v[i+1] += v[i] / MAXC;
v[i] %= MAXC;
}
}
int s = (int) v.size() - 1;
while (s > 0 && v[s] == 0)
s--;
v.resize(s+1);
}
bool isZero() const {
if (v.size() > 1) return false;
return v[0] == 0;
}
bool operator<(const BigInteger &x) const {
if (v.size() != x.v.size())
return v.size() < x.v.size();
for (int i = v.size()-1; i >= 0; i--) {
if (v[i] != x.v[i])
return v[i] < x.v[i];
}
return false;
}
bool operator==(const BigInteger &x) const {
if (v.size() != x.v.size())
return false;
for (int i = v.size()-1; i >= 0; i--)
if (v[i] != x.v[i])
return false;
return true;
}
void print() {
printf("%lld", v[v.size()-1]);
for (int i = (int) v.size() - 2; i >= 0; i--)
printf("%08lld", v[i]);
}
};

int main() {
int N, M, A[128];
BigInteger f[128] = {};
f[0] = BigInteger(1);
for (int i = 1; i < 128; i++)
f[i] = f[i-1] * BigInteger(i);
while (scanf("%d", &N) == 1) {
for (int i = 0; i < N; i++)
scanf("%d", &A[i]);
scanf("%d", &M);

sort(A, A + N);
int dp[10005] = {};
BigInteger dp2[10005] = {};
dp2[0] = BigInteger(1), dp[0] = 0;
for (int i = 0; i < N; i++) {
int x = A[i];
for (int j = M; j >= x; j--) {
if (dp[j] < dp[j-x] + 1 && !dp2[j-x].isZero())
dp[j] = dp[j-x] + 1, dp2[j] = BigInteger(0);
if (dp[j] == dp[j-x] + 1 && !dp2[j-x].isZero())
dp2[j] = dp2[j] + dp2[j-x];
}
}
int a = dp[M];
BigInteger b = dp2[M] * f[a];

printf("%d ", a);
b.print();
puts("");
}
return 0;
}
/*
5
10 50 30 70 60
20
*/