1354F - Summoning Minions[ d p dp dp][费用流]
题意
可以召唤 n n n 个奴才,战场上最多同时可以有 k k k 个奴才
每个奴才权值为 a [ i ] a[i] a[i],召唤到场上后原先场上的奴才权值都可以加上 b [ i ] b[i] b[i]
问要使得最后在场上的权值最大
可以按什么样的顺序放奴才,最大的权值为多少
做法
要使得最后权值尽可能大,可以在场上有 k − 1 k-1 k−1 个奴才的时候,把最后不要再场上的奴才都放场上,这样可以最大化 b [ i ] b[i] b[i] 的价值
最终留在场上的必然是前 k k k 大的 a [ i ] a[i] a[i],问题在于如何放这 k k k 个可以最大化权值
首先将奴才进行排序,将 a [ i ] a[i] a[i] 大的排在前面,这样可以保证取得的前 k k k 个都是 a [ i ] a[i] a[i] 前 k k k 大的
求最大值可以考虑用 d p dp dp
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示到第 i i i 个奴才为止已经选择了 j j j 个奴才上场所可以得到的最大值
利用 v i s [ i ] [ j ] vis[i][j] vis[i][j] 标记 d p [ i ] [ j ] dp[i][j] dp[i][j] 可以选的
转移有两种情况
一种是这个是最后要抛弃的那些奴才
另一种是最后要放在场上的 k k k 个
再逆序找到满足的选择方案
还有另一种做法是费用流
具体可以看我给的链接,毕竟自己还没过
自己写的有点问题(怕不是板子有问题),挠秃头,这两天有空再试一下
输入
3
5 2
5 3
7 0
5 0
4 0
10 0
2 1
10 100
50 10
5 5
1 5
2 4
3 3
4 2
5 1
输出
4
2 1 -1 5
1
2
5
5 4 3 2 1
Code: dp
#include <bits/stdc++.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int maxn = 100 + 5;
struct node{
ll x, y; int id;
bool operator < (const node &ope) const {
return y < ope.y;
}
}a[maxn];
bool vis[maxn][maxn];
ll dp[maxn][maxn];
bool vis2[maxn];
inline void init() {
memset(dp, -1, sizeof(dp));
memset(vis, false, sizeof(vis));
memset(vis2, false, sizeof(vis2));
}
void solve(int n, int k) {
init();
dp[0][0] = 0;
sort(a + 1, a + 1 + n);
for(int i = 1; i <= n; ++i) {
int t = min(i, k);
for(int j = 0; j <= t; ++j) {
if(dp[i - 1][j] >= 0) // 这个作为最后要丢掉的
dp[i][j] = dp[i - 1][j] + (k - 1) * 1ll * a[i].y;
if(j > 0 && dp[i - 1][j - 1] >= 0) {
if(dp[i][j] >= dp[i - 1][j - 1] + a[i].x + (j - 1) * 1ll * a[i].y)
continue;
// 在第 i 个位置选 j 可以得到更大值
dp[i][j] = dp[i - 1][j - 1] + a[i].x + (j - 1) * 1ll * a[i].y;
vis[i][j] = true;
}
}
}
}
void print(int n, int k) {
printf("%d\n", k + (n - k) * 2);
for(int i = n, j = k; i > 0 && j >= 0; --i) {
if(vis[i][j])
vis2[i] = true, --j;
}
int t = 0;
for(int i = 1; i <= n; ++i) {
if(!vis2[i]) continue;
if(++t == k) {
t = a[i].id;
break;
}
printf("%d ", a[i].id);
}
for(int i = 1; i <= n; ++i) {
if(!vis2[i])
printf("%d %d ", a[i].id, -a[i].id);
}
printf("%d\n", t);
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, k;
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++i) {
scanf("%lld%lld", &a[i].x, &a[i].y); a[i].id = i;
}
solve(n, k);
print(n, k);
}
return 0;
}