Codeforces 暑期特訓:我想成為演算法大師 - Week 4
Luke 我什麼都不會

From LI2 Contests Group

Contest 19. Dynamic Programming

C. Grasshoper-K

Problem: C. Grasshoper-K

Solution: GitHub Code

每格的種數由前面 1~k 格加總

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void solve() {
int n, k;
cin >> n >> k;

vector < int > dp(n, 0);
dp[0] = 1;
FOR(i, 1, n){
FOR(j, 1, k+1){
if(i-j>=0){
dp[i] += dp[i-j];
}
}
}

cout << dp[n-1] << endl;
}

E. Grasshopper and Money

Problem: E. Grasshopper and Money

Solution: GitHub Code

  • 解題過程是先用 dp 把最大值求出來,再讓 dp 同時存著最大路徑時走過的點
  • 但是這個解法可能會 MLE,總共花了 86 MB(題目限制是 256 MB)
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
void solve() {
int n, k;
cin >> n >> k;

vector < int > coins(n-2);
FOR(i, 0, n-2) cin >> coins[i];

vector < pair < int, vector < int > > > dp(n);
dp[0] = make_pair(0, vector < int >());
FOR(i, 1, n){
int max_coins = -INT_MAX;
int max_coins_idx = -1;
FOR(j, 1, k+1){
if(i-j<0) break;
if(dp[i-j].F>max_coins){
max_coins = dp[i-j].F;
max_coins_idx = i-j;
}
}

if(i<n-1){
dp[i].F = max_coins + coins[i-1];
}else{
dp[i].F = max_coins;
}

vector < int > v = dp[max_coins_idx].S;
v.PB(max_coins_idx+1);
dp[i].S = v;
}

cout << dp[n-1].F << endl;
cout << dp[n-1].S.size() << endl;
for(int i: dp[n-1].S){
cout << i << ' ';
}
cout << n << endl;
}

J. Milk in Bottles - K

Problem: J. Milk in Bottles - K

Solution: GitHub Code

  • 開一個一維 dp 陣列儲存不同 n 對應到答案的子問題,在轉移狀態時對每個容量的瓶子去裝,找數量最小的出來
  • dp[i] 表示 i 的牛奶最少可以有幾瓶,所以此題所求即為 dp[n]
  • 另外用一個 last_bottles 陣列表示在當前狀態下,選擇哪個瓶子所對應到的子問題,得出的答案數量會最小
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
void solve() {
ifstream fcin("input.txt");
ofstream fcout("output.txt");

int n, k;
fcin >> n >> k;

vector < int > bottles(k);
FOR(i, 0, k) fcin >> bottles[i];

vector < int > dp(n+1, INT_MAX);
dp[0] = 0;

vector < int > last_bottles(n+1, 0);
FOR(i, 1, n+1){
for(int j: bottles){
if(dp[i-j]+1<dp[i] and i-j>=0 and dp[i-j]!=INT_MAX){
dp[i] = dp[i-j] + 1;
last_bottles[i] = j;
}
}
}

if(dp[n]==INT_MAX){
fcout << -1 << endl;
}else{
fcout << dp[n] << endl;

vector < int > ans;
int nn = n;
while(nn>0){
int l = last_bottles[nn];
ans.PB(l);
nn -= l;
}

sort(ALL(ans));
for(int i: ans){
fcout << i << ' ';
}
}
}

L. Array Filling

Problem: L. Array Filling

Solution: GitHub Code

每組 (i, j) 因倍數關係的時候都更新 dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void solve() {
ifstream fcin("input.txt");
ofstream fcout("output.txt");

int n;
fcin >> n;

vector < int > dp(n+5, 1);
for(int i=2; i<=n+1; i++){
for(int j=2; j*j<=i; j++){
if(i%j==0){
dp[i] += dp[j];
if(j*j!=i){
dp[i] += dp[i/j];
}
}
}
}

fcout << dp[n+1] << endl;
}

Contest XX. Greedy

C. Gifts

Problem: C. Gifts

Solution: GitHub Code

  • v 用 pair 來存,分別存著每個物品的總消耗及票卷用下去時能少多少
  • sort(v) 讓總消耗越小的越先取,能讓取的數量最大化
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
void solve() {
int n, b;
cin >> n >> b;

vector < pair < int, int > > v(n);
FOR(i, 0, n){
int p, s;
cin >> p >> s;
v[i].F = p+s;
v[i].S = p/2;
}

sort(ALL(v));

int cnt = 0;
int total = 0;
priority_queue < int > pq;

FOR(i, 0, n){
total += v[i].F;
pq.push(v[i].S);

if(total - pq.top() <= b){
cnt = i + 1;
}else{
break;
}
}

cout << cnt << endl;
}

E. Badgers

Problem: E. Badgers

Solution: GitHub Code

  • 若總共取了 k 個, 則第 i 隻的消耗為 hi + gi * (k-1)
  • 最大化數量為 k 個,所以做 for 迴圈去判斷 k 可以到多少還不會超過 t
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
void solve() {
int n;
cin >> n;

vector < pair < int, int > > v(n);
FOR(i, 0, n) cin >> v[i].F;
FOR(i, 0, n) cin >> v[i].S;

int t;
cin >> t;

int ans = 0;
FOR(k, 1, n+1){
vector < int > costs(n);
FOR(i, 0, n){
costs[i] = v[i].F + v[i].S * (k-1);
}
sort(ALL(costs));

int total = 0;
FOR(i, 0, k){
total += costs[i];
}

if(total <= t){
ans = k;
}else{
break;
}
}

cout << ans << endl;
}
Powered by Hexo & Theme Keep