令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告

令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告
文章图片
大家好,我是小单同学,欢迎交流指正~ 令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告
文章图片
令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告
文章图片

今天上午蓝桥杯圆满落幕,准备了几个月的比赛也终于打完了。今年填空题变成了两道,同学们反映今年难度上升很大,小单也感觉今年难度较大hh,空了两道题。现在给大家分享一下本菜鸡的解题报告,供大家交流。仅供参考哈。
目录
?大家好,我是小单同学,欢迎交流指正~ ?
试题 A: 排列字母
代码详解
试题 B: 特殊时间
代码详解
试题 C: 纸张尺寸
代码详解
试题 D: 求和
代码详解
试题 E: 数位排序
代码详解
试题 F: 选数异或
试题 G: 消除游戏
试题 H: 重新排序
试题 I: 技能升级
总结:
小单同学要去补专业课了QAQ,拜拜~

试题 A: 排列字母

【问题描述】 小蓝要把一个字符串中的字母按其在字母表中的顺序排列。 例如,LANQIAO 排列后为 AAILNOQ。 又如,GOODGOODSTUDYDAYDAYUP 排列后为 AADDDDDGGOOOOPSTUUYYY 。 请问对于以下字符串,排列之后字符串是什么? WHERETHEREISAWILLTHEREISAWAY
这道题无需多言,排个序的事,做这道题之前,我还是很自信的hh。
代码详解
#include #include #include #include #include using namespace std; int main(){ char a[28]; for(int i=0; i<28; ++i)cin>>a[i]; sort(a,a+28); for(int i=0; i<28; ++i){ cout<

试题 B: 特殊时间
【问题描述】 2022 年 2 月 22 日 22:20 是一个很有意义的时间,年份为 2022,由 3 个 2 和 1 个 0 组成,如果将月和日写成 4 位,为 0222,也是由 3 个 2 和 1 个 0 组 成,如果将时间中的时和分写成 4 位,还是由 3 个 2 和 1 个 0 组成。 小蓝对这样的时间很感兴趣,他还找到了其它类似的例子,比如 111 年 10 月 11 日 01:11,2202 年 2 月 22 日 22:02 等等。 请问,总共有多少个时间是这种年份写成 4 位、月日写成 4 位、时间写成 4 位后由 3 个一种数字和 1 个另一种数字组成。注意 1111 年 11 月 11 日 11:11 不算,因为它里面没有两种数字。

更新一下,今天刷题的时候看到类似的题目,学到思路挺简单的其实。就是用字符串构建,答案是212
代码详解
#include #include #include #include using namespace std; typedef long long LL; int d[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; bool check_valid(LL num){ int month = num/10000%10000/100; int day = num/10000%10000%100; if(day <= 0 || day > d[month])return false; if(month <=0 || month > 12)return false; int hour = num % 10000 / 100; int second = num % 10000 % 100; if(hour <= 0 || hour > 24)return false; if(second < 0 || second >= 60)return false; cout << num/100000000 << "年" << month << "月" << day << "日" <<' '<< hour << ":" << second << endl; return true; }int main(){ int res = 0; for(int d1 = 0; d1 <= 9; d1 ++){ string str(12,'0'+d1); for (int d2 = 0; d2 <= 9; d2 ++){ if(d1 == d2)continue; for (int y = 0; y <= 3; y ++){ str[y] = '0' + d2; for(int m = 4; m <= 7; m ++){ str[m] = '0' + d2; for (int d = 8; d<=11; d++){ str[d] = '0' + d2; LL num = atoll(str.c_str()); if(check_valid(num))res ++; str[d] = '0' + d1; } str[m] = '0' + d1; } str[y] = '0' + d1; }} } cout << res; return 0; }

试题 C: 纸张尺寸
【问题描述】 在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm × 841mm,将 A0 纸 沿长边对折后为 A1 纸,大小为 841mm × 594mm,在对折的过程中长度直接取 下整(实际裁剪时可能有损耗)。将 A1 纸沿长边对折后为 A2 纸,依此类推。 输入纸张的名称,请输出纸张的大小。
【输入格式】 输入一行包含一个字符串表示纸张的名称,该名称一定是 A0、A1、A2、 A3、A4、A5、A6、A7、A8、A9 之一。
【输出格式】 输出两行,每行包含一个整数,依次表示长边和短边的长度。
【样例输入 1】 A0
【样例输出 1】 1189 841
这道题也蛮友好哈,模拟即可,先处理掉字符A,后面的数字就是循环的个数,每次选一个大的数/2,(题意说下取整就行), 最后先输出较大的数,再输出较小的数。
代码详解
#include #include #include using namespace std; int main(){ getchar(); int a; cin >> a; int x=1189,y=841; while(a--){ if(x>y)x/=2; else y/=2; } cout<

试题 D: 求和
【问题描述】 给定 n 个整数 a1, a2, · · · , an ,求它们两两相乘再相加的和,即 S = a1 · a2 + a1 · a3 + · · · + a1 · an + a2 · a3 + · · · + an?2 · an?1 + an?2 · an + an?1 · an.
【输入格式】 输入的第一行包含一个整数 n 。 第二行包含 n 个整数 a1, a2, · · · an。
【输出格式】 输出一个整数 S,表示所求的和。请使用合适的数据类型进行运算。
【样例输入】 4 1 3 6 9
【样例输出】 117
【评测用例规模与约定】 对于 30% 的数据,1 ≤ n ≤ 1000,1 ≤ ai ≤ 100。 对于所有评测用例,1 ≤ n ≤ 200000,1 ≤ ai ≤ 1000。
乍一看没啥思路,先想暴力,两层循环枚举所有的数两两相乘,但是此题n为1e5*2,如果时间复杂度为O(n^2),会TLE;
所以 来分析一波,可以发现,S=A m*A m+1+A m*A m+2+......+Am*An;
整理可得S=An*(A1+A2+...+An-1); 就是每一个数乘以它前一项的前缀和。这样可以把时间复杂度优化到O(n),应该可以,不知道对不对, 仅供参考;
代码详解
#include #include using namespace std; typedef long long LL; const int N=200010; int s[N]; int a[N]; int n; int main(){ cin >> n; LL ans=0; for(int i=1; i<=n; ++i){ scanf("%d",&a[i]); s[i]+=s[i-1]+a[i]; } for(int i=n; i>=1; i--){ ans+=(LL)a[i]*s[i-1]; } printf("%lld",ans); return 0; }

试题 E: 数位排序
【问题描述】 小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当 两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时, 将数值小的排在前面。 例如,2022 排在 409 前面,因为 2022 的数位之和是 6,小于 409 的数位 之和 13。 又如,6 排在 2022 前面,因为它们的数位之和相同,而 6 小于 2022。 给定正整数 n,m,请问对 1 到 n 采用这种方法排序时,排在第 m 个的元 素是多少?
【输入格式】 输入第一行包含一个正整数 n。 第二行包含一个正整数 m。
【输出格式】 输出一行包含一个整数,表示答案。
【样例输入】 13 5
【样例输出】 3
【样例说明】 1 到 13 的排序为:1, 10, 2, 11, 3, 12, 4, 13, 5, 6, 7, 8, 9。第 5 个数为 3。 【评测用例规模与约定】 对于 30% 的评测用例,1 ≤ m ≤ n ≤ 300。
对于 50% 的评测用例,1 ≤ m ≤ n ≤ 1000。
对于所有评测用例,1 ≤ m ≤ n ≤ 10^6。
m,n的规模为10^6,应该选择O(nlogn)以内的算法,应该是快排加自定义规则。定义一个结构体,里面两个变量分别是该数字的数为和还有该数字原版的值,重载一下小于号,然后按数位和为第一优先级排序,数值为第二优先级排序。(后来才想到直接用pair就行了,当时考试的时候重载运算不知道为什么传两个参数就是不可以,还debug了半个多小时,麻了)
代码详解
#include #include #include using namespace std; const int N=1e6+5; struct A{ int n1; int s1; bool operator < (const A a)const{ if(a.s1!=s1)return a.s1>s1; if(a.s1==s1)return a.n1>n1; } }a[N]; int main(){ int num1,num2; cin >> num1 >> num2; for(int i=1; i<=num1; ++i){ a[i].n1 = i; int k=a[i].n1; int sum=0; while(k){ sum+=k%10; k/=10; } a[i].s1=sum; } sort(a+1,a+num1+1); cout << a[num2].n1; }

试题 F: 选数异或
【问题描述】 给定一个长度为 n 的数列 A1, A2, · · · , An 和一个非负整数 x,给定 m 次查 询, 每次询问能否从某个区间 [l,r] 中选择两个数使得他们的异或等于 x 。
【输入格式】 输入的第一行包含三个整数 n, m, x 。 第二行包含 n 个整数 A1, A2, · · · , An 。 接下来 m 行,每行包含两个整数 li ,ri 表示询问区间 [li ,ri ] 。
【输出格式】 对于每个询问, 如果该区间内存在两个数的异或为 x 则输出 yes, 否则输出 no。
【样例输入】 4 4 1 1 2 3 4 1 4 1 2 2 3 3 3
【样例输出】 yes no yes no 试题 F: 选数异或 8 第十三届蓝桥杯大赛软件赛省赛 C/C++ 大学 C 组 【样例说明】 显然整个数列中只有 2, 3 的异或为 1。
【评测用例规模与约定】 对于 20% 的评测用例,1 ≤ n, m ≤ 100; 对于 40% 的评测用例,1 ≤ n, m ≤ 1000; 对于所有评测用例,1 ≤ n, m ≤ 100000 ,0 ≤ x < 2 20 ,1 ≤ li ≤ ri ≤ n , 0 ≤ Ai < 2 20。
没想出来。。。写的暴力骗分,两层循环枚举区间,O(n^2),应该可以拿到百分之40把,等大佬更新题解学习一下吧。
试题 G: 消除游戏
【问题描述】 在一个字符串 S 中,如果 S i = S i?1 且 S i , S i+1 ,则称 S i 和 S i+1 为边缘 字符。如果 S i , S i?1 且 S i = S i+1,则 S i?1 和 S i 也称为边缘字符。其它的字符 都不是边缘字符。 对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符 (操作后可能产生新的边缘字符)。 请问经过 2 64 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则 输出 EMPTY。
【输入格式】 输入一行包含一个字符串 S 。
【输出格式】 输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY。
【样例输入 1】 edda 【样例输出 1】 EMPTY
【样例输入 2】 sdfhhhhcvhhxcxnnnnshh 【样例输出 2】 s
【评测用例规模与约定】 对于 25% 的评测用例,|S | ≤ 103 ,其中 |S | 表示 S 的长度; 对于 50% 的评测用例,|S | ≤ 104 ; 对于 75% 的评测用例,|S | ≤ 105 ; 对于所有评测用例,|S | ≤ 106,S 中仅含小写字母。
这题和下一题都没做。我写异或数列那道暴力的时候,数组下标写错了,第一考试可能有点紧张?D了四十多分钟硬是没搞出来,后来才发现,我那个悔恨 啊,导致后来时间就来不及了,心也开始浮躁了,不然可以再写两道的(想不出来写暴力也行 啊!懊恼中!)。
试题 H: 重新排序
【问题描述】 给定一个数组 A 和一些查询 Li , Ri,求数组中第 Li 至第 Ri 个元素之和。 小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查 询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可 以增加多少?
【输入格式】 输入第一行包含一个整数 n。 第二行包含 n 个整数 A1, A2, · · · , An,相邻两个整数之间用一个空格分隔。 第三行包含一个整数 m 表示查询的数目。 接下来 m 行,每行包含两个整数 Li、Ri ,相邻两个整数之间用一个空格分 隔。 【
输出格式】 输出一行包含一个整数表示答案。
【样例输入】 5 1 2 3 4 5 2 1 3 2 5
【样例输出】 4
试题 I: 技能升级
【问题描述】 小蓝最近正在玩一款 RPG 游戏。他的角色一共有 N 个可以加攻击力的技 能。其中第 i 个技能首次升级可以提升 Ai 点攻击力,以后每次升级增加的点数 都会减少 Bi。? Ai Bi ? (上取整) 次之后,再升级该技能将不会改变攻击力。 现在小蓝可以总计升级 M 次技能,他可以任意选择升级的技能和次数。请 你计算小蓝最多可以提高多少点攻击力?
【输入格式】 输入第一行包含两个整数 N 和 M。 以下 N 行每行包含两个整数 Ai 和 Bi。 【输出格式】 输出一行包含一个整数表示答案。
【样例输入】 3 6 10 5 9 2 8 1
【样例输出】 47 【评测用例规模与约定】 对于 40% 的评测用例,1 ≤ N, M ≤ 1000; 对于 60% 的评测用例,1 ≤ N ≤ 10^4 , 1 ≤ M ≤ 10^7; 对于所有评测用例,1 ≤ N ≤ 10^5,1 ≤ M ≤ 2 × 10^9,1 ≤ Ai , Bi ≤ 10^6。

就剩半小时了,又写的暴力。(懊恼+99999,数据友好的话也许能拿60的分?)
#include #include #include #include using namespace std; int n,m; const int N=1e5+5; int c[N],cnt[N]; #define x first #define y second typedef pair > PII; pair > a[N]; int main(){ cin >> n >> m; //m是可以升级的次数 int ans=0; for(int i=1; i<=n; ++i){ scanf("%d%d",&a[i].x,&a[i].y.x); if(a[i].x%a[i].y.x==0)a[i].y.y=a[i].x/a[i].y.x; else a[i].y.y = a[i].x/a[i].y.x + 1; } sort(a+1,a+n+1,greater() ); for(int i=1; i<=m; ++i){ ans+=a[1].x; a[1].x-=a[1].y.x; cnt[a[1].x]++; if(cnt[a[1].x]>=a[1].y.y)a[1].x=0; sort(a+1,a+n+1,greater()); } cout<

最后一题还是暴力,有一个条件还放错位置了,放到循环里面了,应该放到循环外面的。(懊恼+9999999)
总结: 小单第一次打蓝桥杯,。虽然这次成绩可能不太理想,考试的时候是真的有点紧张嘞,之前学的算法全想不起来用,一看没时间了,就想着,暴力,暴力,暴力。最主要的是暴力还写错了一道,我哭。所以下次再有类似的比赛一定要沉下心来,不能慌,会就是会不会就是不会,不要太把得失放在心上。也要更细心一点,不能再出现这种一个数组下标写错,Debug了将近四十分钟的情况。不过也 没什么啦,通过这次比赛我开阔了眼界,认识到了自己的不足,也学到了很多的知识。接下来继续努力学习新知识,坚持每天一道算法题,并且定期总结和复盘。希望各位同学都能取到好的成绩,没取到好成绩的同学也不要灰心(比如我),和本菜鸡一起努力吧!

令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告
文章图片


小单同学要去补专业课了QAQ,拜拜~ 【令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告】令人快乐的刷题小妙招|【2022第十三届蓝桥杯】c/c++ 大学c组 解题报告
文章图片

    推荐阅读