2019牛客暑期多校训练营(第六场)J Upgrading Technology【贪心+优先队列】【前缀和】
题意:
初始有n个技能,初始等级为0,有1~m m个技能等级,升级需要成本,当n个技能都升级到某个等级以上就会给予奖励
升级的成本和给予的奖励可能为负数,请问得到最大利润的状态下的利润是多少
题目链接:
https://ac.nowcoder.com/acm/contest/886/J
题解:
我的做法是对每个技能的升级到某个等级的费用先记录下来,就是对每个技能都做一遍前缀和,放进优先队列里面
即每个技能一个优先队列,成本最小的优先级最高
然后对全部技能再做一遍前缀和,算出全部技能都只到达某个等级时此刻的利润是多少
然后枚举等级,把该等级后的升级最多可以获得的利润(不包括升级奖励)算出来相加,减掉最小的就是答案
AC_code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1000+10;
ll mapp[maxn][maxn], d[maxn], sum[maxn], Sum[maxn][maxn];
priority_queue<pair<ll, ll> > q[maxn];
int main() {
int t, cas = 0;
scanf("%d", &t);
while(t--) {
ll n, m;
scanf("%lld %lld", &n, &m);
memset(sum, 0, sizeof(sum));
memset(Sum, 0, sizeof(Sum));
for(int i = 1; i <= n; i++) {
while(!q[i].empty()) {
q[i].pop();
}
q[i].push(make_pair(Sum[i][0], 0));
for(int j = 1; j <= m; j++) {
scanf("%lld", &mapp[i][j]);
Sum[i][j] = Sum[i][j-1] - mapp[i][j];
q[i].push(make_pair(Sum[i][j], j));
sum[j] -= mapp[i][j];
}
}
d[0] = 0;
for(int i = 1; i <= m; i++) {
scanf("%lld", &d[i]);
d[i] += d[i-1];
sum[i] += sum[i-1];
}
ll ans = 0;
ll tmp = 0;
for(int k = 0; k <= m; k++) {
tmp = d[k];
ll maxx = tmp + sum[k];
ll b = 0,h = 0,minn;
for(int i = 1; i <= n; i++) {
while(!q[i].empty() && q[i].top().second < k) {
q[i].pop();
}
b = q[i].top().first - Sum[i][k];
if(i == 1) {
minn = b;
} else {
minn = min(minn, b);
}
h += b;
}
ans = max(ans, maxx + h - minn);
}
printf("Case #%d: %lld\n", ++cas, ans);
}
}