您的位置:首页 > 其它

51 nod 1625 夹克爷发红包【贪心、二进制枚举】

2017-08-16 14:42 211 查看

1625 夹克爷发红包

题意:

1.给你一个 n 行 m 列的二维矩阵,代表每个人的初始红包值。

2.夹克爷可以至多给 k 行 / 列的每个人发红包,每一个价值为 x,同时会覆盖掉初始红包。

3.求所有人的最大红包值总和。

4.数据范围1≤n≤10,1≤m≤200,1≤x≤109,0≤k≤n+m

思路:

1.可以看到行最多只有10行,所以可以用二进制暴力枚举行,1代表给该行发超级红包。

2.每次枚举,除去超级红包的行(num),累计每一列的红包总和,扔进优先队列。

3.这时至多还能 发k−num个超级红包,每次拿最小列值que.top()和x×(n−num)比较,累计较大值。

4.累计剩余的列,返回结果,维护最大值。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int mp[20][210];
LL col[210];
int n, m, x, k;
int calbit(int x) {
int sum = 0;
while(x) {
if(x & 1) sum++;
x >>= 1;
}
return sum;
}
LL update(int sta) {
int num = calbit(sta);
if(num > k) return 0;
memset(col, 0, sizeof(col)); //累计剩余行中,每一列的和
LL sum = 0;
for(int j = 0; j < n; ++ j) {
if((sta & (1 << j))) {
sum += 1LL * x * m;
} else {
for(int k = 0; k < m; ++ k)
col[k] += mp[j][k];
}
}
priority_queue<LL, vector<LL>, greater<LL> >que;
//存除去更新的行后,每一列的值,从小到大弹出
for(int k = 0; k < m; ++ k)
que.push(col[k]);
int ls = k - num;
LL dig = 1LL * x * (n - num);
//最多更新ls次
for(int j = 0; j < ls; ++ j) {
if(que.empty()) break;
sum += max(que.top(), dig);
que.pop();
}
//剩余的列弹出来
while(!que.empty()) sum += que.top(), que.pop();
return sum;
}
int main() {
scanf("%d%d%d%d", &n, &m, &x, &k);
LL ans = 0;
for(int i = 0; i < n; ++ i) {
for(int j = 0; j < m; ++ j) {
scanf("%d", &mp[i][j]);
ans += mp[i][j];
}
}
//枚举行
for(int sta = 0; sta < (1 << n); ++ sta) {
ans = max(ans, update(sta));
}
cout << ans << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  51nod