第 46 届 ICPC 国际大学生程序设计竞赛亚洲区域赛(上海)I. Steadily Growing Steam(DP)
链接:https://ac.nowcoder.com/acm/contest/24872/I
来源:牛客网
题目描述
Alice enjoys playing a card game called Steadily Growing Steam (as known as SGS).
In this game, each player will play different roles and have different skills. Players get cards from the deck and use them to play the game. Each card has a numeric label tit_iti, the point number. In addition, each card has a value viv_ivi.
Now Alice is playing this game with Bob. According to the skill of Alice's role, she can have Bob display nnn cards from the top of the deck. After that, Bob must choose some cards from the nnn cards and split the chosen cards into two sets that the sum of the cards' point numbers in the two sets are equal. In other words, if one of the sets is SSS and another is TTT , S∩T=∅S\cap T=\emptysetS∩T=∅ and ∑i∈Sti=∑j∈Ttj\sum_{i\in S} t_i=\sum _{j\in T}t_j∑i∈Sti=∑j∈Ttj (Note that S∪T={1,2,⋯n}S\cup T = {1,2,\cdots n}S∪T={1,2,⋯n} is not necessary). Then, Alice gets all of the cards in set SSS and Bob gets the cards in set TTT.
However, according to the skill of Bob's role, before choosing the two sets, he can choose at most kkk different cards and double their point numbers. In other words, he can choose a sequence {a1,a2,⋯ ,ar}, (1≤a1<a2<⋯<ar≤n, 0≤r≤k){a_1,a_2,\cdots,a_r},,(1\le a_1<a_2<\cdots <a_r\le n,, 0\le r\le k){a1,a2,⋯,ar},(1≤a1<a2<⋯<ar≤n,0≤r≤k) and for each i (1≤i≤r)i,(1\le i \le r)i(1≤i≤r) , change tait_{a_i}tai into 2tai2t_{a_i}2tai. After that he can continue choosing the two sets.
Alice and Bob are partners in this game. Now given the nnn cards from the deck, they want to know the maximum possible sum of the values of the cards they finally get. In other words, determine the maximum ∑i∈S∪Tvi\sum_{i\in S \cup T}v_i∑i∈S∪Tvi among all valid schemes(choose cards to double their point numbers, then choose cards and split them into two sets S,TS,TS,T of the same point number sum) and output it.
输入描述:
The first line contains two integers n (1≤n≤100)n\,(1\le n \le 100)n(1≤n≤100) and k (0≤k≤n)k\,(0\le k \le n)k(0≤k≤n), denoting the number of the displayed cards and the maximum number of cards that Bob can choose to double their point numbers, respectively.
The i+1i+1i+1 line contains two integers vi (∣vi∣≤109)v_i\,(|v_i|\le 10^9)vi(∣vi∣≤109) and ti (1≤ti≤13)t_i\,(1\le t_i \le 13)ti(1≤ti≤13), denoting the value and the point number of the iii-th card, respectively.
输出描述:
Output one line containing one integer, denoting the maximum sum of the value of the cards that Alice or Bob can get.
示例1
输入
[复制](javascript:void(0)😉
4 1
10 1
-5 3
5 1
6 1
输出
[复制](javascript:void(0)😉
21
dp,设dp[i, j, w]为当前考虑了前i件物品,j件翻倍且t之和为w的最大的价值。为了方便起见,对于一个物品如果其放在A集合则设t为正,否则t为负。这样最终要求的值就是\(max_{i = 0\ to\ k}dp[n][i][0]\)。转移方程如下:
因为数组下标不能取负数,因此可以加一个偏移量\(bias = 2600\),这样最终要求的就是\(max_{i = 0\ to\ k}dp[n][i][2600]\)了。
注意dp数组的初始化以及转移时的可行性判断(dp数组对应值不为-INF时才能发生转移)。
#include <bits/stdc++.h>
#define INF 100000000
#define int long long
using namespace std;
int n, k, dp[105][105][26 * 210], v[105], t[105];//dp[i][j][k]为考虑前i件,j件物体体积翻倍且体积和为k的最大的value
signed main() {
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> v[i] >> t[i];
}
for(int i = 0; i <= n; i++) {
for(int j = 0; j <= k; j++) {
for(int w = 0; w <= 26 * n + 2600; w++) {
dp[i][j][w] = -INF;
if(w == 2600) dp[i][j][w] = 0;
}
}
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= k; j++) {
for(int w = 0; w <= 26 * n + 2600; w++) {
dp[i][j][w] = max(dp[i][j][w], dp[i - 1][j][w]);
if(w - t[i] >= 0) dp[i][j][w] = max(dp[i][j][w], dp[i - 1][j][w - t[i]] + v[i]);
if(w + t[i] <= 2600 + n * 26) dp[i][j][w] = max(dp[i][j][w], dp[i - 1][j][w + t[i]] + v[i]);
if(j - 1 >= 0 && w + 2 * t[i] <= 2600 + n * 26) dp[i][j][w] = max(dp[i][j][w], dp[i - 1][j - 1][w + 2 * t[i]] + v[i]);
if(j - 1 >= 0 && w - 2 * t[i] >= 0) dp[i][j][w] = max(dp[i][j][w], dp[i - 1][j - 1][w - 2 * t[i]] + v[i]);
}
}
}
int ans = -INF;
for(int i = 0; i <= k; i++) {
ans = max(ans, dp[n][i][2600]);
}
if(ans != -INF) cout << ans;
else cout << 0;
}