题目描述
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 ti, the point number. In addition, each card has a value vi.
Now Alice is playing this game with Bob. According to the skill of Alice's role, she can have Bob display n 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 S and another is T , S∩T=∅ and ∑i∈Sti=∑j∈Ttj (Note that S∪T={1,2,⋯n} is not necessary). Then, Alice gets all of the cards in set S and Bob gets the cards in set T.
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) and for each i(1≤i≤r) , change tai into 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 among all valid schemes(choose cards to double their point numbers, then choose cards and split them into two sets S,T of the same point number sum) and output it.
输入描述:
The first line contains two integers n(1≤n≤100) and 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+1 line contains two integers vi(∣vi∣≤10^9) and 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
输入
4 1 10 1 -5 3 5 1 6 1
输出
21
题意: 有n张卡片,每张卡都有一个价值wi和一个点数vi,现在拥有t次将点数翻倍的机会,需要从n张卡中选出两个集合A和B,使得集合中卡片点数之和相等,求这两个集合价值之和的最大值。
分析: 设dp[i][j][k]表示考虑前i张卡片,集合A点数和减集合B点数和为j,最多k次翻倍机会时两集合价值和的最大值,状态转移方程考虑所有的决策,一共有六种不同的决策,第一种是第i张卡不翻倍且不把第i张卡放入任何集合,第二种是第i张卡翻倍且不把第i张卡放入任何集合,这种情况不如第一种情况优,因为翻倍后第i张卡又不进入集合,所以相当于白白浪费一次翻倍机会,故舍掉这种情况,第三种是把第i张卡翻倍并放入A集合,第四种是把第i张卡不翻倍并放入A集合,第五种是把第i张卡翻倍并放入B集合,第六种是把第i张卡不翻倍并放入B集合,因此一共有五条状态转移方程,具体请见代码部分。
接下来考虑初始化,首先价值会出现负数,因此要先把所有dp值置无穷小,之后可以把n = 1的情况单独列出来,这样会比较清晰。n = 1时同样是按照上面的六种情况分析,不能漏掉情况,具体请见代码。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
using namespace std;
int n, t, dp[105][5205][105], w[105], v[105];
//dp数组第二维记录集合A-B的分数
signed main()
{
cin >> n >> t;
for(int i = 1; i <= n; i++)
scanf("%lld%lld", &w[i], &v[i]);
//这里用memset会超时
for(int i = 0; i <= n; i++)
for(int j = 0; j <= 5200; j++)
for(int k = 0; k <= t; k++)
dp[i][j][k] = -inf;
//把n = 1的情况单独更新出来
for(int k = 0; k <= t; k++)
{
//选第一张卡
if(k != 0)
{
dp[1][2600+2*v[1]][k] = w[1];
dp[1][2600-2*v[1]][k] = w[1];
}
dp[1][2600-v[1]][k] = w[1];
dp[1][2600+v[1]][k] = w[1];
//不选第一张卡
dp[1][2600][k] = 0;
}
for(int i = 2; i <= n; i++)
for(int j = 0; j <= 5200; j++)
for(int k = 0; k <= t; k++)
{
//不翻倍且不把第i张卡放入任何集合
dp[i][j][k] = dp[i-1][j][k];
//翻倍且不把第i张卡放入任何集合的情况不优,舍掉
//dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k-1]);
//把第i张卡翻倍放入A集合
if(k >= 1 && j-2*v[i] >= 0)
dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-2*v[i]][k-1]+w[i]);
//把第i张卡不翻倍放入A集合
if(j-v[i] >= 0)
dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-v[i]][k]+w[i]);
//把第i张卡翻倍放入B集合
if(k >= 1 && j+2*v[i] <= 5200)
dp[i][j][k] = max(dp[i][j][k], dp[i-1][j+2*v[i]][k-1]+w[i]);
//把第i张卡不翻倍放入B集合
if(j+v[i] <= 5200)
dp[i][j][k] = max(dp[i][j][k], dp[i-1][j+v[i]][k]+w[i]);
}
cout << dp[n][2600][t];
return 0;
}