题目链接:点我啊╭(╯^╰)╮
题目大意:
n
n
n 张牌,最多放
k
k
k 张,可以放了之后删掉
每张牌初始战力为
a
i
a_i
ai,上场后场上所有牌的战力增加
b
i
b_i
bi
输出使最终战力和最大的方案
解题思路:
鉴于昨天
d
p
dp
dp 把
i
i
i 写成
c
n
t
cnt
cnt 找了三个小时,这道题又没想出来,所以还是写一下吧
很明显先上
k
−
1
k-1
k−1 张牌之后开始
b
u
f
f
buff
buff 最优,最后再上场一张牌即可
因此按照
b
i
b_i
bi 排序之后就可直接选取了,因为
b
i
b_i
bi 大的肯定放在后面好
看了一下别人的方法有各种各样的建图方法,仿佛欣赏名画一样
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 为到
i
i
i 为止,选了
j
j
j 张牌的最优值
若选取这张牌作为
b
u
f
f
buff
buff 牌,则只考虑
b
u
f
f
buff
buff
若选取这张牌一直保留到最后,则要考虑
a
i
a_i
ai 和
b
u
f
f
buff
buff
然后记录一下路径即可
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 80;
int n, k, T, chos[maxn];
int dp[maxn][maxn], path[maxn][maxn];
struct node{
int a, b, id;
bool operator < (const node &A) {
return b < A.b;
}
} a[maxn];
signed main() {
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &k);
for(int i=1; i<=n; i++) scanf("%d%d", &a[i].a, &a[i].b), a[i].id = i;
sort(a+1, a+1+n);
memset(dp, 128, sizeof(dp));
memset(chos, 0, sizeof(chos));
memset(path, 0, sizeof(path));
dp[0][0] = 0;
for(int i=1; i<=n; i++)
for(int j=0; j<=min(i, k); j++){
if(dp[i-1][j] >= 0){
dp[i][j] = dp[i-1][j] + a[i].b * (k - 1);
}
if(j > 0 && dp[i-1][j-1] >= 0){
if(dp[i][j] >= dp[i-1][j-1]+a[i].a+a[i].b*(j-1)) continue;
dp[i][j] = dp[i-1][j-1] + a[i].a + a[i].b * (j - 1);
path[i][j] = 1;
}
}
for(int i=n, j=k; i; i--)
if(path[i][j]) chos[a[i].id] = 1, j--;
printf("%d\n", k + (n - k) * 2);
int cnt = 0, last = 0;
for(int i=1; i<=n; i++){
if(!chos[a[i].id]) continue;
if(++cnt == k){
last = a[i].id;
break;
}
printf("%d ", a[i].id);
}
for(int i=1; i<=n; i++){
if(chos[a[i].id]) continue;
printf("%d %d ", a[i].id, -a[i].id);
}
printf("%d\n", last);
}
}