HAUT2021蓝桥杯专题练习第四周记录——贪心
HAUT2021蓝桥杯专题练习第四周记录——贪心
贪心好难啊,证明啥都不会,全程膜拜大佬555
经过这次的练习也学到了很多吧,起码一些基础的贪心就知道了,但是吧,就这周说明白了是贪心还做不出来,更别说以后连贪心都不告诉了……算法之路,道阻且艰。
题目列表
- HAUT2021蓝桥杯专题练习第四周记录——贪心
- A 外币兑换(计蒜客T1524)
- B 今年暑假不AC(HDU2037)
- C 混合牛奶(P1208[USACO1.3])
- D 最小距离字符串(计蒜客T1279)
- E 程序设计:轻重搭配(计蒜客A2227)
- F 纪念品分组(P1094[NOIP2007])
- G 翻硬币(计蒜客T1395)
- H Before an Exam(CF4B)
- I 均分纸牌(P1031[NOIP2002])
- J Milking cows(CF383A)
- K Binary Period(CF1342B)
- L 删数问题(P1106)
- M Knights of a Polygonal Table(CF9948B)
- N Strange Birthday Party(CF1470A)
- O Heaters(CF1066B)
- P Lawnmower(CF115B)
- Q New Year Book Reading(CF500C)
- R 序列(P1645)
- S Clique Problem(CF527D)
- T Make It Equal(CF1065C)
- 总结
A 外币兑换(计蒜客T1524)
按照常规的前面几道超级水的题。
这题直接找出最大值的月然后全部换完就没了。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{double N, m = 0;cin >> N;for (int i = 0; i < 12; i++){double tmp;cin >> tmp;if (tmp > m)m = tmp;}printf("%.2f\n", m * N);return 0;
}
B 今年暑假不AC(HDU2037)
一道非常典型的贪心模板题,也是我为数不多会做的
按照结束时间进行排序,然后贪心选结束时间尽量早的就行了。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
P p[200];
int main()
{int n;while (cin >> n){if (n == 0)break;for (int i = 0; i < n; i++)cin >> p[i].second >> p[i].first;int cnt = 0;//按照结束时间进行排序sort(p, p + n);int ed = 0;for (int i = 0; i < n; i++){//如果开始时间大于结束时间,就去看这一部if (ed <= p[i].second) {cnt++;ed = p[i].first;}}cout << cnt << endl;}return 0;
}
C 混合牛奶(P1208[USACO1.3])
贪心每次都买单价小的。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
P p[5100];
int main()
{int N, M;cin >> N >> M;for (int i = 0; i < M; i++)cin >> p[i].first >> p[i].second;//按照单价排序sort(p, p + M);int res = 0, cnt = 0;for (int i = 0; i < M; i++){//牛奶数量不够if (cnt + p[i].second <= N){cnt += p[i].second;res += p[i].second * p[i].first;}else{cnt = N - cnt;res += cnt * p[i].first;break;}}cout << res << endl;return 0;
}
D 最小距离字符串(计蒜客T1279)
对于每个字符都贪心选用最小的代价。
一共三个字符,也就分三种情况,全都相等(+0),或者有两个相等(+1),或者一个都不相等(+2)。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{string A, B, C;cin >> A >> B >> C;int n = A.length();int res = 0;for (int i = 0; i < n; i++){bool isok = false;if (A[i] == B[i] && A[i] != C[i])isok = true;if (A[i] == C[i] && A[i] != B[i])isok = true;if (B[i] == C[i] && A[i] != B[i])isok = true;if (A[i] == B[i] && A[i] == C[i]) //全都相等continue;if (isok) //有两个相等res++;else //都不同res += 2;}cout << res << endl;return 0;
}
E 程序设计:轻重搭配(计蒜客A2227)
因为重的人无法找到自己2倍体重的人,所以应该优先让轻的和比较轻的去匹配,比较重的和重的去匹配。这样能保证匹配的人数最多。证明的话不会
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 500100;
int arr[max_n];
int n;
int main()
{cin >> n;for (int i = 0; i < n; i++)cin >> arr[i];sort(arr, arr + n);int cnt = 0;for (int i = 0, j = n / 2; i < n / 2; i++){while (j < n && arr[i] * 2 > arr[j]) //前面的比较大,后面的往后移j++;if (j >= n)break;cnt++;j++;}int res = n - cnt;cout << res << endl;return 0;
}
F 纪念品分组(P1094[NOIP2007])
先把便宜的和贵的尽可能多的进行匹配,然后再加上落单的纪念品。
AC代码
#include <bits/stdc++.h>
using namespace std;
int arr[30010];
int main()
{int w, n;cin >> w >> n;for (int i = 0; i < n; i++)cin >> arr[i];sort(arr, arr + n);int j = 0, cnt = 0;for (int i = n - 1; i >= 0; i--){//便宜和贵的匹配,用过的标记为-1if (arr[i] + arr[j] <= w && arr[i] != -1 && arr[j] != -1){arr[i] = -1;arr[j] = -1;cnt++;j++;}}for (int i = 0; i < n; i++){//记录落单的纪念物if (arr[i] != -1)cnt++;}cout << cnt << endl;return 0;
}
G 翻硬币(计蒜客T1395)
从左到右每次翻两个模拟进行下去就行了。保证一枚硬币不会被翻转超过两次(被动翻一次,主动翻一次),不然的话肯定不是最优解了。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{string s, goal;cin >> s >> goal;int cnt = 0;for (int i = 0; i < s.length() - 1; i++){if (s[i] != goal[i]){if (s[i] == '*')s[i] = 'o';elses[i] = '*';if (s[i + 1] == '*')s[i + 1] = 'o';elses[i + 1] = '*';cnt++;}}if (s[s.length() - 1] != goal[s.length() - 1])cout << "No Answer." << endl;elsecout << cnt << endl;return 0;
}
H Before an Exam(CF4B)
先每天把最少的时间都选上,然后遍历用剩余时间填满到最大值。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
//min max
P p[35];
int main()
{int d, sumTime;int smin = 0, smax = 0;cin >> d >> sumTime;for (int i = 0; i < d; i++){cin >> p[i].first >> p[i].second;smin += p[i].first;smax += p[i].second;}if (smin > sumTime || smax < sumTime) //不满足条件,直接退出{cout << "NO" << endl;return 0;}cout << "YES" << endl;sumTime -= smin; //每天最少选最小值for (int i = 0; i < d; i++){//剩下的值比最大值要大if (sumTime >= (p[i].second - p[i].first)) {sumTime -= (p[i].second - p[i].first);cout << p[i].second << " ";}else //剩下值不如最大值大{cout << p[i].first + sumTime << " ";sumTime = 0;}}cout << endl;return 0;
}
I 均分纸牌(P1031[NOIP2002])
先把平均值算出来,然后让数减去平均值看差了多少,只要总和0就至少要移动一次。
AC代码
#include <bits/stdc++.h>
using namespace std;
int arr[110];
int main()
{int n, sum = 0;cin >> n;for (int i = 0; i < n; i++){cin >> arr[i];sum += arr[i];}int tot = sum / n, res = 0;for (int i = 0; i < n; i++)arr[i] -= tot; //剩下的数sum = 0;for (int i = 0; i < n; i++){sum += arr[i]; //加上现在的数if (sum == 0)continue;//现在还不够res++;}cout << res << endl;return 0;
}
J Milking cows(CF383A)
这道题和 Number of Ways(CF466C) 这道题挺像的感觉,上次那个是找1/3的点,再找到2/3之后匹配每一个1/3,这道题是找到向右的牛,再找到向左的牛之后损失每一个向右的牛的牛奶量。
AC代码
#include <bits/stdc++.h>
using namespace std;
//和那道找三分之一和的题很像
int main()
{int n;cin >> n;long long sum = 0, res = 0;for (int i = 0; i < n; i++){int tmp;cin >> tmp;if (tmp == 1) //向右sum++;else //向左,有一个向右的,所有向左的都得损失res += sum;}cout << res << endl;return 0;
}
K Binary Period(CF1342B)
除去全是0和全是1的情况,其余答案都可以由"01"字符串构成。如果目标有一个数,那我就给他一个"01"。这样就能保证,目标串是我这个串的子串了,而且肯定是有周期的。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{string s = "01";int T;cin >> T;while (T--){string goal;cin >> goal;string res;int n = goal.size(), sum = 0;for (int i = 0; i < n; i++)sum += goal[i] - '0'; //计算1的个数if (sum == 0 || sum == n) //全是0或者全是1cout << goal << endl;else{string res;for (int i = 0; i < n; i++)res += s;cout << res << endl;}}return 0;
}
L 删数问题(P1106)
每次都去删前面比后面大的数。
分析过程放到代码里面了。
AC代码
#include <bits/stdc++.h>
using namespace std;
/* 分析过程//都与自己后边的数比较1 7 5 4 3 8小 大 大 大 小 无 这样就直接扫一遍就可以把大的全部删除了(7 5 4)剩下的是按照增序排序的,那么就直接删除比较大的数就是答案
*/
int main()
{string s;cin >> s;int k;cin >> k;int n = s.size();for (k; k > 0; k--){for (int i = 0; i < s.size(); i++){if (s[i] > s[i + 1]) //如果后面的数比前面的数小,删除前面的数{s.erase(i, 1);break;}}}while (s[0] == '0') //前导零问题s.erase(0, 1);if (s.size() == 0)s = "0";cout << s << endl;return 0;
}
M Knights of a Polygonal Table(CF9948B)
让骑士,尽可能的去杀比自己能力低,并且带着的钱比较多的骑士,这样就能保证每个骑士获得的钱比较多了。
详细的思路放到代码里面了。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 100100;
struct Knight
{//能力 金币数 结果金币数 自身的序号long long p, c, res, number;
} knight[max_n];int main()
{int n, k;cin >> n >> k;for (int i = 0; i < n; i++){cin >> knight[i].p;knight[i].number = i;}for (int i = 0; i < n; i++){cin >> knight[i].c;knight[i].res = knight[i].c;}//按能力值(p)排序sort(knight, knight + n, [](Knight k1, Knight k2) {if (k1.p != k2.p)return k1.p < k2.p;return k1.c < k2.c;});//保留待鲨的骑士vector<int> tmp;tmp.push_back(knight[0].c);for (int i = 1; i < n; i++) //第i个可以要前i-1个的c{int m = 0, t = k;while (t--) //把前面这k个鲨了{knight[i].res += tmp[m];m++;if (m == tmp.size()) //如果已经把比自己弱的鲨完了break;}tmp.push_back(knight[i].c);//大到小排序sort(tmp.begin(), tmp.end(), [](int v1, int v2) {return v1 > v2;});if (tmp.size() > k) //如果数量大于ktmp.pop_back();}//按照序号还原顺序sort(knight, knight + n, [](Knight k1, Knight k2) {return k1.number < k2.number;});for (int i = 0; i < n; i++)cout << knight[i].res << " ";cout << endl;return 0;
}
N Strange Birthday Party(CF1470A)
礼物只有一个,而且序号大的可以选择比自己序号小的礼物,也就是说,序号大的可以选择便宜的礼物,那么就让序号比较大的先选择是送钱还是送礼物。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 300100;
int k[max_n];
int c[max_n];int main()
{int t;cin >> t;while (t--){int n, m;cin >> n >> m;for (int i = 1; i <= n; i++)cin >> k[i];for (int i = 1; i <= m; i++)cin >> c[i];//从大到小排序,sort(k + 1, k + 1 + n, [](int a, int b) {return a > b;});long long res = 0, r = 1;for (int i = 1; i <= n; i++){if (c[k[i]] > c[r]) //相比送钱,买礼物更便宜,所以选择送礼物并且让礼物指针右移{res += c[r];r++;}elseres += c[k[i]];}cout << res << endl;}return 0;
}
O Heaters(CF1066B)
这题,但是做懵了可能,楞是理解错题意了。
题目大致意思就是让覆盖所有区间,那么直接就找看哪里没有被覆盖,然后在覆盖的的范围里面找尽可能往右的灯,这样需要的灯就会比较少了。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 1010;
int arr[max_n];
//题目大意:覆盖所有区间
int main()
{int n, r;cin >> n >> r;for (int i = 1; i <= n; i++)cin >> arr[i];int res = 0;for (int i = 1; i <= n; i++){bool isok = false;for (int j = min(n, i + r - 1); j >= max(i - r + 1, 1); j--) //找最右边能开灯的地方{if (arr[j] == 1) //开灯{res++;i = j + r - 1; //直接到最后面覆盖不到的地方找isok = true;break;}}if (!isok){cout << "-1" << endl;return 0;}}cout << res << endl;return 0;
}
P Lawnmower(CF115B)
容易知道的是,奇数行要从左向右,偶数行要从右向左。
有一个做法是保留最左边和最后边的草,然后直接一下到头就行了。但是我这样做的时候WA了,因为有些地方需要注意,像空行
下面是参考一个大佬做法写的。一步一步走,计算曼哈顿距离。
AC代码
#include <bits/stdc++.h>
using namespace std;
char Map[155][155];int main()
{int n, m;cin >> n >> m;for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++)cin >> Map[i][j];}//奇数往右,偶数向左//上次的行数和列数int starti = 1, startj = 1, res = 0;for (int i = 1; i <= n; i++){if (i % 2 == 1) //奇数行{for (int j = 1; j <= m; j++){if (Map[i][j] == 'W') //如果这一行有草,那么直接推到草那里{res += abs(starti - i) + abs(startj - j);starti = i;startj = j;}}}else //偶数行{for (int j = m; j >= 1; j--){if (Map[i][j] == 'W') //如果这一行有草,那么直接推到草那里{res += abs(starti - i) + abs(startj - j);starti = i;startj = j;}}}}cout << res << endl;return 0;
}
Q New Year Book Reading(CF500C)
书的顺序就是第一次读到这本书的顺序,先找好顺序,然后可以放到vector里面,使用erase和insert两个函数进行书的调换。
AC代码
#include <bits/stdc++.h>
using namespace std;
int w[520]; //书重
int d[1010]; //读哪一本书
vector<int> order; //摆书的顺序
int arr[520]; //辅助记录顺序int main()
{int n, m;cin >> n >> m;memset(arr, 0, sizeof(arr));for (int i = 1; i <= n; i++)cin >> w[i];int j = 1;for (int i = 1; i <= m; i++){cin >> d[i];if (arr[d[i]] == 0){arr[d[i]]++;order.push_back(d[i]);j++;}}int res = 0;for (int i = 1; i <= m; i++) //读书顺序{for (j = 0; j < order.size(); j++) //找书{if (d[i] != order[j])res += w[order[j]]; //加上前面的书重else //找到书了之后更新顺序{order.erase(order.begin() + j);order.insert(order.begin(), d[i]);break;}}}cout << res << endl;return 0;
}
R 序列(P1645)
放进结构体里面按照右边界排序,然后遍历一下结构体里面的范围,看里面是否有这么多的数,没有的话从右往左取数。
AC代码
#include <bits/stdc++.h>
using namespace std;
struct QJ
{int l, r, c;} qj[1010];
int vis[1010];
int main()
{int n;cin >> n;memset(vis, 0, sizeof(vis));for (int i = 0; i < n; i++)cin >> qj[i].l >> qj[i].r >> qj[i].c;//按照r排序sort(qj, qj + n, [](QJ q1, QJ q2) {return q1.r < q2.r;});int res = 0;for (int i = 0; i < n; i++){int cnt = 0;for (int j = qj[i].l; j <= qj[i].r; j++) //先看里面数字够不够那么多{if (vis[j])qj[i].c--;}if (qj[i].c > 0) //不够,因为是至少有ci个数,所以有可能ci<0{for (int j = qj[i].r; j >= qj[i].l; j--) //从右向左取{if (!vis[j]){vis[j] = 1;qj[i].c--;res++;if (qj[i].c == 0) //够了break;}}}}cout << res << endl;return 0;
}
S Clique Problem(CF527D)
这道题进行移项处理,转换成了区间覆盖问题,区间覆盖问题直接把右边界进行排序。
当然这都是大佬说的,我就只会按这写……
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 200010;
struct Point
{//坐标 权值 左边界 有边界//xi - wi >= xj + wj//l >= rint x, w, l, r;
} p[max_n];
int main()
{int n;cin >> n;for (int i = 0; i < n; i++){cin >> p[i].x >> p[i].w;p[i].l = p[i].x - p[i].w;p[i].r = p[i].x + p[i].w;}//按照右边界边界排序sort(p, p + n, [](Point p1, Point p2) {if (p1.r != p2.r)return p1.r < p2.r;return p1.l < p2.l;});//区间覆盖问题int res = 0, last = -1 << 30;for (int i = 0; i < n; i++){if (p[i].l >= last){res++;last = p[i].r;}}cout << res << endl;return 0;
}
T Make It Equal(CF1065C)
找出最高的塔和最低的塔,然后慢慢砍到最低的那个塔就行了。如果砍了一层发现还有剩余,那么就继续砍下一层。总之尽可能多的使用完就行了。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 200100;
int h[max_n];
int cnt[max_n];
int main()
{int n, k;cin >> n >> k;//最低的塔高和最高的塔高int min = 1 << 30;int max = 0;for (int i = 0; i < n; i++){cin >> h[i];if (h[i] < min)min = h[i];if (h[i] > max)max = h[i];cnt[h[i]]++; //h[i]这么高的塔有多少个}int res = 0, sum = 0;//从高的往低的砍for (int i = max; i > min; i--){cnt[i] += cnt[i + 1]; //砍到了第i层if (sum + cnt[i] > k){res++;sum = cnt[i]; //如果不能砍了,就另加一次,来砍这一刀}elsesum += cnt[i];}if (sum == 0) //如果sum==0代表不用砍剩下的1刀了,反之需要再砍一刀cout << res << endl;elsecout << res + 1 << endl;return 0;
}
总结
贪心题不知道怎么贪心的话是怎么想都想不出来,知道了之后就感觉好水(
因为过年的问题,做完了前面几道题之后就直接给自己放假玩去了233后面的题是后来再写的,不过感觉还行,学到了很多吧,虽然不知道自己会不会用,反正一点一点来得了。
下周DP,挺好。
HAUT2021蓝桥杯专题练习第四周记录——贪心相关推荐
- 【蓝桥杯专题】 贪心(C++ | 洛谷 | acwing | 蓝桥)
菜狗现在才开始备战蓝桥杯QAQ 文章目录 [蓝桥杯专题] (C++ | 洛谷 | acwing | 蓝桥) 1055. 股票买卖 II AcWing 104. 货仓选址 传递糖果 AcWing 112 ...
- 蓝桥杯官网刷题记录python
蓝桥杯官网刷题记录python 由于很多题都会在2020.2021.2022年省赛出现,有的在前面文章里做过的这里就不会再说了 一.空间 小蓝准备用 256MB 的内存空间开一个数组,数组的每个元素都 ...
- 【蓝桥杯专题】 DP(C++ | 洛谷 | acwing | 蓝桥)
菜狗现在才开始备战蓝桥杯QAQ 文章目录 编程实现动态规划的状态转移方程时, 务必分清楚阶段. 状态与决策, 三者应该按照由外向内的顺序依次循环!! ----蓝书 背包问题 01背包 AcWing 3 ...
- 蓝桥杯专题之并查集篇
题目列表: 2020年:网络分析,七段码 合根植物 1.网络分析 题目描述 小明正在做一个网络实验.他设置了 n 台电脑,称为节点,用于收发和存储数据.初始时,所有节点都是独立的,不存在任何连接.小明 ...
- 蓝桥杯专题-试题版-【十进制转十六进制】【十六进制转八进制】【十六进制转十进制】【数的读法】
点击跳转专栏=>Unity3D特效百例 点击跳转专栏=>案例项目实战源码 点击跳转专栏=>游戏脚本-辅助自动化 点击跳转专栏=>Android控件全解手册 点击跳转专栏=> ...
- 蓝桥杯专题-试题版含答案-【荷兰国旗问题】【正三角形的外接圆面积】【比较字母大小】【车牌号】
点击跳转专栏=>Unity3D特效百例 点击跳转专栏=>案例项目实战源码 点击跳转专栏=>游戏脚本-辅助自动化 点击跳转专栏=>Android控件全解手册 点击跳转专栏=> ...
- 蓝桥杯专题(一)《C语言》
一.年号字串 题目链接https://www.lanqiao.cn/problems/605/learning/ 小明用字母 A 对应数字 1,B 对应 2,以此类推,用 Z 对应 26.对于 27 ...
- 蓝桥杯 历届试题 翻硬币(贪心)
历届试题 翻硬币 时间限制:1.0s 内存限制:256.0MB 问题描述 小明正在玩一个"翻硬币"的游戏. 桌上放着排成一排的若干硬币.我们用 * 表示正面,用 o 表示反面( ...
- 蓝桥杯算法训练KAc给糖果贪心-python题解
KAC给糖果(贪心) 问题描述 kAc有n堆糖果,每堆有A[i]个. kAc说你只能拿m次糖果,聪明的你当然想要拿最多的糖果来吃啦啦啦~ //第二天,kAc问你还想吃糖果么?(嘿嘿嘿)说着眼角路出奇怪 ...
最新文章
- ES6中的Promise详解
- FPGA学习之路—应用程序—原码二位乘法器及Verilog代码分析
- 网络连接的netstat命令
- 使用友元,编译出错fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1786) 的解决...
- [RBA开发系列一] 建立http 请求的process
- [bbk2193] 第34集 - Chapter 09-Optimizing Sore Perations(03)
- c语言linux系统宏,Linux下C语言中的预定义宏
- mysql 数据类型总结
- 免费好用的录屏工具 —— EVCapture
- 【福利】论机房如何关闭方正软件保护卡
- 数学原理(The Principles of Mathmatics)
- Java接口组装一台计算机编写各组件厂商分别实现CPU,EMS,HardDisk接口
- 基于MinimaxAlpha-Beta剪枝和强化学习的播棋(Mancala)AI
- 13 Python函数进阶
- 1005: 整数幂 Java
- Android仿QQ列表滑动
- 亲情友情爱情:《悲惨世界》第四部《卜吕梅街的柔情和圣德尼街的史诗》/人性:《悲惨世界》第五部《冉阿让》摘录...
- LTE-5G学习笔记8---PRACH参数规划
- 空气源热泵控制系统解决方案
- ORCALE DDL,DML,DQL命令
热门文章
- mybatis-sql语句莫名其妙被加上limit分页条件或未执行查询条件
- 面试第一问:简单做个自我介绍吧,怎么回答才让面试官频频点头?
- 【hardware】什么是H桥电路?
- GDT、GDTR、LDT、LDTR的理解 [zz]
- Machine Learning 机器学习
- java多用户商城系统架构之第一篇——总的介绍
- 浏览器提示代理服务器出现问题,或则地址有误
- OSChina 周三乱弹 —— 国家命运与个人命运
- configure: error: Cannot find ldap libraries in /usr/lib
- win10下如何使用的debug