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; }
相关文章推荐
- 1625 夹克爷发红包(二进制枚举运用)
- 51nod 1625 夹克爷发红包(状压枚举+贪心)
- 51 Nod 1625 夹克爷发红包
- 51NOD 1625 夹克爷发红包 枚举+贪心
- 51nod 1625夹克爷发红包(贪心+枚举)
- 51 nod 1672 区间交(枚举 贪心)
- 51nod1625 夹克爷发红包 枚举+贪心
- 51 nod 1378 夹克老爷的愤怒 树形dp + 贪心
- 1625 夹克爷发红包 贪心 + 暴力 + 思维
- 51NOD 1625 夹克爷发红包 (贪心+dfs)
- 1625 夹克爷发红包 51HOD
- 51nod 1625 夹克爷发红包,暴力+贪心
- 51nod 1625 夹克爷发红包【思维+暴力+贪心】好题~
- 51Nod - 1625 夹克爷发红包(暴力+贪心)
- HihoCoder 1271 舰队游戏(二进制枚举、贪心)
- 51nod 1625 夹克爷发红包
- 夹克老爷发红包(51nod1625)
- 51nod 1625 夹克爷发红包
- 51 nod 1385 凑数字(贪心+构造)
- 51 nod 1091 贪心