• 第十三届蓝桥杯省赛C++ C组《全题目+题解》


    填空题一般都是找规律题目,耐下心来慢慢分析即可。

    第一题《排列字母》

    【问题描述】

    小蓝要把一个字符串中的字母按其在字母表中的顺序排列。
    例如,LANQIAO 排列后为AAILNOQ。
    又如,GOODGOODSTUDYDAYDAYUP 排列后为AADDDDDGGOOOOPSTUUYYY。
    请问对于以下字符串,排列之后字符串是什么?
    WHERETHEREISAWILLTHEREISAWAY

    【答案提交】

    本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

    【思路】简单模拟

    【代码】

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. string s;
    7. cin >> s;
    8. sort(s.begin(),s.end());
    9. cout << s;
    10. return 0;
    11. }

    【答案】

    AAAEEEEEEHHHIIILLRRRSSTTWWWY

    第二题《特殊时间》

    【问题描述】

    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不算,因为它里面没有两种数字。

    【答案提交】

    本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

    【思路】模拟

    【代码】

    1. 1月:0111 4*1*4=16
    2. 2月:0222 4*1*4=16
    3. 3月——9月:0 日最大不会超过31日,也不能出现00日的情况。
    4. 10月:1011 4*1*4=16
    5. 11月:1101 1110 1112 1113 1114 1115 1116 1117 1118 1119 1121
    6. 4*1*4 4*1*4 4*1*4 4*1*3 4*1*3 4*1*3 4*1*2 4*1*2 4*1*2 4*1*2 4*1*4 =16+16+16+12+12+12+8+8+8+8+16=64+36+32=132
    7. 12月:1211 1222 4*1*4 + 4*1*4 =32
    8. 总 : 16+16+16+132+32 = 212;

    【答案】

    212

    程序设计题尽可能打暴力

    第三题《纸张尺寸》

    【问题描述】

    在 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

    【输入样例2】

    A1

    【输出样例2】

    841

    594

    【思路】简单模拟

    【代码】

    1. #include
    2. using namespace std;
    3. int main(){
    4. string str;
    5. cin >> str;
    6. int length = 1189,width=841;
    7. int n = str[1] - '0';
    8. while(n--){
    9. if(length > width) length /= 2;
    10. else width /= 2;
    11. }
    12. if(length > width){
    13. printf("%d\n%d",length,width);
    14. }else{
    15. printf("%d\n%d",width,length);
    16. }
    17. return 0;
    18. }

    第四题《求和》

    【问题描述】

    给定 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,表示所求的和。

    请使用合适的数据类型进行运算。

    【数据范围】

    对于 30% 的数据,1≤n≤1000,1≤ai≤100。
    对于所有评测用例,1≤n≤200000,1≤ai≤1000。

    【输入样例】

    4
    1 3 6 9

     【输出样例】

    117

    【思路】简单模拟 / 前缀和

    【代码】

    1. #include
    2. using namespace std;
    3. const int N = 200010;
    4. int a[N],n;
    5. long long res;
    6. int main(){
    7. long long s = 0;
    8. scanf("%d",&n);
    9. for(int i = 1;i<=n;i++) {
    10. scanf("%d",&a[i]);
    11. s += a[i];
    12. }
    13. for(int i = 1;i
    14. s -= a[i];
    15. res += a[i] * s;
    16. }
    17. printf("%lld",res);
    18. return 0;
    19. }

    第五题《数位排序

    【问题描述】

    小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。

    当两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,将数值小的排在前面。

    例如,2022 排在 409 前面,因为 2022 的数位之和是 6,小于 409 的数位之和 13。

    又如,6 排在 2022 前面,因为它们的数位之和相同,而 6 小于 2022。

    给定正整数 n,m,请问对 1 到 n 采用这种方法排序时,排在第 m 个的元素是多少?

    【输入格式】

    输入第一行包含一个正整数 n。

    第二行包含一个正整数 m。

    【输出格式】

    输出一行包含一个整数,表示答案。

    【数据范围】

    对于 30% 的评测用例,1≤m≤n≤300。
    对于 50% 的评测用例,1≤m≤n≤1000。
    对于所有评测用例,1≤m≤n≤10的6次方。

    【输入样例】

    13

    5

    【输出样例】

    3

    【样例解释】

    1 到 13 的排序为:1,10,2,11,3,12,4,13,5,6,7,8,9。

    第 5 个数为 3。

    【思路】自定义排序规则 + 提取每一位数字。

    对如何提取每一位数字不熟悉的可以参考AcWing. 466 / NOIP2016普及组《回文日期》(C++)

    【代码】

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 1000010;
    5. int n,m;
    6. int w[N],s[N];
    7. bool cmp(int a,int b){
    8. if(s[a] != s[b]) return s[a]
    9. return a < b;
    10. }
    11. int main(){
    12. scanf("%d%d",&n,&m);
    13. for(int i = 1;i<=n;i++){
    14. w[i] = i;
    15. for(int j = i;j;j /= 10){
    16. s[i] += j % 10;
    17. }
    18. }
    19. sort(w+1,w+n+1,cmp);
    20. printf("%d",w[m]);
    21. return 0;
    22. }

    第六题《选数异或

    【问题描述】

    给定一个长度为 n 的数列 A1,A2,⋅⋅⋅,An 和一个非负整数 x,给定 m 次查询,每次询问能否从某个区间 [l,r] 中选择两个下标不同的数使得他们的异或等于 x。

    【输入格式】

    输入的第一行包含三个整数 n,m,x。

    第二行包含 n 个整数 A1,A2,⋅⋅⋅,An。

    接下来 m 行,每行包含两个整数 li,ri 表示询问区间 [li,ri]。

    【输出格式】

    对于每个询问,如果该区间内存在两个数的异或为 x 则输出 yes,否则输出 no。

    【数据范围】

    对于 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次方

    【输入样例】

    4 4 1
    1 2 3 4
    1 4
    1 2
    2 3
    3 3

    【输出样例】

    yes
    no
    yes
    no

    【样例解释】

    显然整个数列中只有 2,3 的异或为 1。

    【思路】

    状态表示:last[i] : a[i] 左侧与 a[i] 配对的最近一个数的下标 ,g[i] : f[i]前缀的最大值 

    状态转移:g[i]  = max(f[1],f[2] ..... f[i]);

    补充 :a ^ b = x 等价于 b = a ^ x 。

    【代码】

    1. #include
    2. using namespace std;
    3. int n,m,x;
    4. const int N = 100010,M = (1 << 20) + 10;
    5. int last[M],g[N];
    6. int main(){
    7. scanf("%d%d%d",&n,&m,&x);
    8. for(int i = 1;i<=n;i++){
    9. int a;
    10. scanf("%d",&a);
    11. g[i] = max(g[i-1],last[a^x]);
    12. last[a] = i;
    13. }
    14. while(m--){
    15. int l,r;
    16. scanf("%d%d",&l,&r);
    17. if(g[r] >= l) puts("yes");
    18. else puts("no");
    19. }
    20. return 0;
    21. }

    第七题《消除游戏

    【问题描述】

    在一个字符串 S 中,如果 Si=Si−1 且 Si≠Si+1,则称 Si 和 Si+1 为边缘字符。

    如果 Si≠Si−1且 Si=Si+1,则 Si−1 和 Si 也称为边缘字符。

    其它的字符都不是边缘字符。

    对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符(操作后可能产生新的边缘字符)。

    请问经过 2的64次方 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则输出 EMPTY

    【输入格式】

    输入一行包含一个字符串 S。

    【输出格式】

    输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY

    【数据范围】

    对于 25% 的评测用例,|S|≤10的3次方,其中 |S| 表示 S 的长度;
    对于 50% 的评测用例,|S|≤10的4次方;
    对于 75% 的评测用例,|S|≤10的5次方;
    对于所有评测用例,|S|≤10的6次方,S 中仅含小写字母。

    【输入样例1】

    edda

    【输出样例1】

    EMPTY

    【输入样例2】

    sdfhhhhcvhhxcxnnnnshh

    【输出样例2】

    s

    【思路】链表

    【代码】

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. const int N = 1000010;
    7. int n;
    8. char s[N];
    9. int l[N], r[N];
    10. vector<int> q, w;
    11. bool st[N];
    12. void insert(int k)
    13. {
    14. if (!st[k])
    15. {
    16. st[k] = true;
    17. w.push_back(k);
    18. }
    19. }
    20. void filter_dels()
    21. {
    22. w.clear();
    23. for (int k: q)
    24. {
    25. int a = l[k], b = k, c = r[k];
    26. if (s[a] == s[b] && s[b] != s[c] && s[c] != '#')
    27. {
    28. insert(b);
    29. insert(c);
    30. }
    31. else if (s[a] != s[b] && s[b] == s[c] && s[a] != '#')
    32. {
    33. insert(a);
    34. insert(b);
    35. }
    36. }
    37. }
    38. int main()
    39. {
    40. scanf("%s", s + 1);
    41. n = strlen(s + 1);
    42. s[0] = s[n + 1] = '#';
    43. for (int i = 1; i <= n; i ++ )
    44. {
    45. l[i] = i - 1, r[i] = i + 1;
    46. q.push_back(i);
    47. }
    48. r[0] = 1, l[n + 1] = n;
    49. while (true)
    50. {
    51. filter_dels();
    52. if (w.empty()) break;
    53. q.clear();
    54. for (int k: w)
    55. {
    56. int a = l[k], b = k, c = r[k];
    57. if (!st[a] && a && (q.empty() || a != q.back())) q.push_back(a);
    58. if (!st[c] && c != n + 1) q.push_back(c);
    59. r[a] = c, l[c] = a;
    60. }
    61. }
    62. if (r[0] == n + 1) puts("EMPTY");
    63. else
    64. {
    65. for (int i = r[0]; i != n + 1; i = r[i])
    66. printf("%c", s[i]);
    67. }
    68. return 0;
    69. }

    第八题《重新排序

    【问题描述】

    给定一个数组 A 和一些查询 Li,Ri,求数组中第 Li 至第 Ri 个元素之和。

    小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查询结果的和尽可能地大。

    小蓝想知道相比原数组,所有查询结果的总和最多可以增加多少?

    【输入格式】

    输入第一行包含一个整数 n。

    第二行包含 n 个整数 A1,A2,⋅⋅⋅,An,相邻两个整数之间用一个空格分隔。

    第三行包含一个整数 m 表示查询的数目。

    接下来 m 行,每行包含两个整数 Li、Ri,相邻两个整数之间用一个空格分隔。

    【输出格式】

    输出一行包含一个整数表示答案。

    【数据范围】

    对于 30% 的评测用例,n,m≤50;
    对于 50% 的评测用例,n,m≤500;
    对于 70% 的评测用例,n,m≤5000;
    对于所有评测用例,1≤n,m≤10的5次方,1≤Ai≤10的6次方,1≤Li≤Ri≤n。

    【输入样例】

    5
    1 2 3 4 5
    2
    1 3
    2 5

    【输出样例】

     4

     【样例解释】

    原来的和为 6+14=20,重新排列为 (1,4,5,2,3) 后和为 10+14=24,增加了 4。

    【思路】差分 + 贪心 + 排序不等式

    不了解差分的可以参考【模板】AcWing797.《差分》(C++)

    不了解排序不等式的可以参考模板:排序不等式】AcWing913.《排队打水》(C++)

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. typedef long long LL;
    6. const int N = 100010;
    7. int n, m;
    8. int w[N], s[N];
    9. int main()
    10. {
    11. scanf("%d", &n);
    12. for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
    13. scanf("%d", &m);
    14. while (m -- )
    15. {
    16. int l, r;
    17. scanf("%d%d", &l, &r);
    18. s[l] ++, s[r + 1] -- ;
    19. }
    20. for (int i = 1; i <= n; i ++ )
    21. s[i] += s[i - 1];
    22. LL sum1 = 0;
    23. for (int i = 1; i <= n; i ++ )
    24. sum1 += (LL)s[i] * w[i];
    25. LL sum2 = 0;
    26. sort(s + 1, s + n + 1);
    27. sort(w + 1, w + n + 1);
    28. for (int i = 1; i <= n; i ++ )
    29. sum2 += (LL)s[i] * w[i];
    30. printf("%lld\n", sum2 - sum1);
    31. return 0;
    32. }

    第九题《技能升级

    【问题描述】

    小蓝最近正在玩一款 RPG游戏。

    他的角色一共有 N 个可以加攻击力的技能。

    其中第 i 个技能首次升级可以提升 Ai 点攻击力,以后每次升级增加的点数都会减少 Bi。

    ⌈Ai/Bi⌉(上取整)次之后,再升级该技能将不会改变攻击力。

    现在小蓝可以总计升级 M 次技能,他可以任意选择升级的技能和次数。

    请你计算小蓝最多可以提高多少点攻击力?

    【输入格式】

    输入第一行包含两个整数 N 和 M。

    以下 N 行每行包含两个整数 Ai 和 Bi。

    【输出格式】

    输出一行包含一个整数表示答案。

    【数据范围】

    对于 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次方。

    【输入样例】

    3 6
    10 5
    9 2
    8 1

    【输出样例】

    47

    【思路】贪心 + 多路归并 + 二分

    【代码】

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. typedef long long LL;
    6. const int N = 100010;
    7. int n, m;
    8. int a[N], b[N];
    9. bool check(int mid)
    10. {
    11. LL res = 0;
    12. for (int i = 0; i < n; i ++ )
    13. if (a[i] >= mid)
    14. res += (a[i] - mid) / b[i] + 1;
    15. return res >= m;
    16. }
    17. int main()
    18. {
    19. scanf("%d%d", &n, &m);
    20. for (int i = 0; i < n; i ++ ) scanf("%d%d", &a[i], &b[i]);
    21. int l = 0, r = 1e6;
    22. while (l < r)
    23. {
    24. int mid = l + r + 1 >> 1;
    25. if (check(mid)) l = mid;
    26. else r = mid - 1;
    27. }
    28. LL res = 0, count = 0;
    29. for (int i = 0; i < n; i ++ )
    30. if (a[i] >= r)
    31. {
    32. int cnt = (a[i] - r) / b[i] + 1;
    33. count += cnt;
    34. int end = a[i] - (cnt - 1) * b[i];
    35. res += (LL)(a[i] + end) * cnt / 2;
    36. }
    37. printf("%lld\n", res - (count - m) * r);
    38. return 0;
    39. }

    第十题《重复的数

    【问题描述】

    给定一个数列 A=(a1,a2,⋅⋅⋅,an),给出若干询问,每次询问某个区间 [li,ri] 内恰好出现 ki 次的数有多少个。

    【输入格式】

    输入第一行包含一个整数 n 表示数列长度。

    第二行包含 n 个整数 a1,a2,⋅⋅⋅,an,表示数列中的数。

    第三行包含一个整数 m 表示询问次数。

    接下来 m 行描述询问,其中第 i 行包含三个整数 li,ri,ki 表示询问 [li,ri] 区间内有多少数出现了 ki次。

    【输出格式】

    输出 m 行,分别对应每个询问的答案。

    【数据范围】

    对于 20% 的评测用例,n,m≤500,1≤a1,a2,⋅⋅⋅,an≤1000;
    对于 40% 的评测用例,n,m≤5000;
    对于所有评测用例,1≤n,m≤100000,1≤a1,a2,⋅⋅⋅,an≤100000,1≤li≤ri≤n,1≤ki≤n。

    【输入样例】

    3
    1 2 2
    5
    1 1 1
    1 1 2
    1 2 1
    1 2 2
    1 3 2

    【输出样例】

    1
    0
    2
    0
    1

    【思路】莫队

    【代码】

    1. #include
    2. using namespace std;
    3. const int N = 101000;
    4. int sq;
    5. struct query {
    6. int l, r, id, cnt;
    7. bool operator<(const query& t)const
    8. {
    9. if (l / sq != t.l / sq)
    10. return l < t.l;
    11. if (l / sq & 1)
    12. return r < t.r;
    13. return r > t.r;
    14. }
    15. }q[N];
    16. int cur, cnt[N], a[N], ans[N], s[N];
    17. int l = 1, r, n, m;
    18. void add(int p)
    19. {
    20. cnt[s[p]]--;
    21. cnt[++s[p]]++;
    22. }
    23. void del(int p)
    24. {
    25. cnt[s[p]]--;
    26. cnt[--s[p]]++;
    27. }
    28. int main()
    29. {
    30. scanf("%d", &n);
    31. sq = sqrt(n);
    32. for (int i = 1; i <= n; i++)
    33. scanf("%d", &a[i]);
    34. scanf("%d", &m);
    35. for (int i = 0; i < m; i++)
    36. {
    37. int l, r, k;
    38. scanf("%d%d%d", &l, &r, &k);
    39. q[i] = { l, r, i, k };
    40. }
    41. sort(q, q + m);
    42. for (int i = 0; i < m; i++)
    43. {
    44. while (l > q[i].l)
    45. add(a[--l]);
    46. while (r < q[i].r)
    47. add(a[++r]);
    48. while (l < q[i].l)
    49. del(a[l++]);
    50. while (r > q[i].r)
    51. del(a[r--]);
    52. ans[q[i].id] = cnt[q[i].cnt];
    53. }
    54. for (int i = 0; i < m; i++)
    55. printf("%d\n", ans[i]);
    56. return 0;
    57. }
  • 相关阅读:
    文件管理系统-----文件的逻辑结构
    程序员凭本事赚钱被没收所得,是否体现了“重刑主义”?
    pytorch-gpu(Anaconda3+cuda+cudnn)
    未来电商怎么走,是腾讯视频号,还是抖音小店?你更看好谁?
    【kubernetes】使用virtual-kubelet扩展k8s
    赶紧进来看看!!!你一定要会做的八道经典指针笔试题!!!
    最全分布式面试题整理
    12.1 使用键盘鼠标监控钩子
    网页JS自动化脚本(七)使用在线jQuery来操作元素
    Windows10 子系统 (WSL) 或 docker wsl 模式 修改虚拟磁盘目录
  • 原文地址:https://blog.csdn.net/m0_74172965/article/details/136683620