深圳幻海软件技术有限公司 欢迎您!

蓝桥杯——2018第九届C/C++真题[省赛][B组]

2023-04-29

目录第几天明码乘积尾零测试次数快速排序递增三元组螺旋折线  日志统计全球变暖 乘积最大  第几天思路:这道题是蓝桥杯爱考的老题了,咱们可以通过电脑自带的计算器做也可以用excel做,最后我再提供一下代码吧计算器excel  代码:

目录

第几天

明码

乘积尾零

测试次数

快速排序

递增三元组

螺旋折线 

 日志统计

全球变暖 

乘积最大 


 

第几天

思路:这道题是蓝桥杯爱考的老题了,咱们可以通过电脑自带的计算器做也可以用excel做,最后我再提供一下代码吧

计算器

excel

  

代码:我把计算各种日期问题的模板代码放在这里,大家可以练习练习

  1. #include<iostream>
  2. using namespace std;
  3. class Date {
  4. public:
  5. int GetMonthDay(int year, int month) const
  6. {
  7. static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  8. int day = monthDayArray[month];
  9. // 365天 5小时+
  10. if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
  11. {
  12. day += 1;
  13. }
  14. return day;
  15. }
  16. Date(int year, int month, int day)
  17. {
  18. _year = year;
  19. _month = month;
  20. _day = day;
  21. if (!(_year >= 0
  22. && (month > 0 && month < 13)
  23. && (day > 0 && day <= GetMonthDay(year, month))))
  24. {
  25. cout << "非法日期->";
  26. // this->Print();
  27. Print();
  28. }
  29. }
  30. void Print() const
  31. {
  32. cout << _year << "-" << _month << "-" << _day << endl;
  33. }
  34. bool operator>(const Date& d) const
  35. {
  36. if (_year > d._year)
  37. {
  38. return true;
  39. }
  40. else if (_year == d._year && _month > d._month)
  41. {
  42. return true;
  43. }
  44. else if (_year == d._year && _month == d._month && _day > d._day)
  45. {
  46. return true;
  47. }
  48. else
  49. {
  50. return false;
  51. }
  52. }
  53. // d1 == d2
  54. bool operator==(const Date& d) const
  55. {
  56. return _year == d._year
  57. && _month == d._month
  58. && _day == d._day;
  59. }
  60. // d1 < d2
  61. bool operator<(const Date& d) const
  62. {
  63. return !(*this >= d);
  64. }
  65. // d1 >= d2
  66. bool operator>=(const Date& d) const
  67. {
  68. return *this > d || *this == d;
  69. }
  70. bool operator<=(const Date& d) const
  71. {
  72. return !(*this > d);
  73. }
  74. bool operator!=(const Date& d) const
  75. {
  76. return !(*this == d);
  77. }
  78. // d1 += 100
  79. Date& operator+=(int day)
  80. {
  81. if (day < 0)
  82. {
  83. return *this -= -day;
  84. }
  85. _day += day;
  86. while (_day > GetMonthDay(_year, _month))
  87. {
  88. _day -= GetMonthDay(_year, _month);
  89. ++_month;
  90. if (_month == 13)
  91. {
  92. _month = 1;
  93. _year++;
  94. }
  95. }
  96. return *this;
  97. }
  98. // d1 + 100
  99. Date operator+(int day) const
  100. {
  101. Date ret(*this);
  102. //ret.operator+=(day);
  103. ret += day;
  104. return ret;
  105. }
  106. // d1 -= 10
  107. Date& operator-=(int day)
  108. {
  109. if (day < 0)
  110. {
  111. return *this += -day;
  112. }
  113. _day -= day;
  114. while (_day <= 0)
  115. {
  116. --_month;
  117. if (_month == 0)
  118. {
  119. --_year;
  120. _month = 12;
  121. }
  122. _day += GetMonthDay(_year, _month);
  123. }
  124. return *this;
  125. }
  126. // d1 - 10
  127. Date operator-(int day) const
  128. {
  129. Date ret(*this);
  130. ret -= day;
  131. return ret;
  132. }
  133. // ++d1;
  134. Date& operator++()
  135. {
  136. *this += 1;
  137. return *this;
  138. }
  139. // d1++; 后置为了跟前置++,进行区分
  140. // 增加一下参数占位,跟前置++,构成函数重载
  141. Date operator++(int)
  142. {
  143. Date ret(*this);
  144. *this += 1;
  145. return ret;
  146. }
  147. // --d1;
  148. Date& operator--()
  149. {
  150. *this -= 1;
  151. return *this;
  152. }
  153. Date operator--(int)
  154. {
  155. Date ret(*this);
  156. *this -= 1;
  157. return ret;
  158. }
  159. // offerDay - today
  160. int operator-(const Date& d) const
  161. {
  162. Date max = *this;
  163. Date min = d;
  164. int flag = 1;
  165. if (*this < d)
  166. {
  167. max = d;
  168. min = *this;
  169. flag = -1;
  170. }
  171. int count = 0;
  172. while (min != max)
  173. {
  174. ++min;
  175. ++count;
  176. }
  177. return count * flag;
  178. }
  179. private:
  180. int _year;
  181. int _month;
  182. int _day;
  183. };
  184. int main()
  185. {
  186. Date d1(2000, 1, 1);
  187. Date d2(2000, 5, 4);
  188. int count = d2 - d1;
  189. cout << count << endl;
  190. return 0;
  191. }

答案:125 

明码

  1. 4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
  2. 16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16
  3. 4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
  4. 0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4
  5. 4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64
  6. 16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128
  7. 0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0
  8. 2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0
  9. 1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0
  10. 0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0

思路:主要看懂题目,共10行,每行32个十进制数字,一行代表一个汉字,就是先要把这些十进制转化为二进制,若为负数则转换为补码(负数的二进制就是负数的补码),输入直接复制即可,运行结果为“九的九次方等于多少?”最后再根据要求求出整数答案。

推荐博客:bitset用法小结 - 自为风月马前卒 - 博客园

  1. #include<iostream>
  2. #include<bitset>
  3. using namespace std;
  4. int main() {
  5. int n, m;
  6. while (cin >> n >> m) {
  7. bitset<8> t;//t为二进制8位 biset<length> t
  8. t = n;//将n赋给t,即将n转化为8位二进制
  9. cout << t;//输出n的8位二进制
  10. t = m;//将m赋给t,即将n转化为8位二进制
  11. cout << t << endl;//输出n的8位二进制
  12. }
  13. return 0;
  14. }

这个就是主代码了;可以看一下运行结果:

 这样并不能看的很清楚,我们再稍微改进一下

代码:

  1. #include<iostream>
  2. #include<bitset>
  3. #include<string>
  4. using namespace std;
  5. int main()
  6. {
  7. int n, m;
  8. int len;
  9. string temp;
  10. while (cin >> n >> m)
  11. {
  12. bitset<8> t;
  13. t = n;
  14. temp = t.to_string();
  15. len = temp.size();
  16. for (int i = 0; i < len; i++)
  17. {
  18. if (temp[i] == '0')
  19. {
  20. cout << " ";
  21. }
  22. else {
  23. cout << "*";
  24. }
  25. }
  26. t = m;
  27. temp = t.to_string();
  28. len = temp.size();
  29. for (int i = 0; i < len; i++)
  30. {
  31. if (temp[i] == '0')
  32. {
  33. cout << " ";
  34. }
  35. else {
  36. cout << "*";
  37. }
  38. }
  39. cout << endl;
  40. }
  41. return 0;
  42. }

答案:387420489

乘积尾零

思路:这个题不能直接乘,我们要想办法转化,

两个数相乘

2*5=10, 2*1*5*1=10,          有一个2,一个5;

4*25=100,2*2*5*5=10        有两个2,二个5;

8*125,2*2*2*5*5*5=1000   有三个2,三个5;

求尾零的个数就是求2与5的对数(即两者中最小数为两者的对数)

代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. int main()
  5. {
  6. int num[10 * 10] = { 5650, 4542, 3554, 473, 946, 4114, 3871, 9073, 90, 4329,
  7. 2758, 7949, 6113, 5659, 5245, 7432, 3051, 4434, 6704, 3594,
  8. 9937, 1173, 6866, 3397, 4759, 7557, 3070, 2287, 1453, 9899,
  9. 1486, 5722, 3135, 1170, 4014, 5510, 5120, 729, 2880, 9019,
  10. 2049, 698, 4582, 4346, 4427, 646, 9742, 7340, 1230, 7683,
  11. 5693, 7015, 6887, 7381, 4172, 4341, 2909, 2027, 7355, 5649,
  12. 6701, 6645, 1671, 5978, 2704, 9926, 295, 3125, 3878, 6785,
  13. 2066, 4247, 4800, 1578, 6652, 4616, 1113, 6205, 3264, 2915,
  14. 3966, 5291, 2904, 1285, 2193, 1428, 2265, 8730, 9436, 7074,
  15. 689, 5510, 8243, 6114, 337, 4096, 8199, 7313, 3685, 211 };
  16. int count_2 = 0, count_5 = 0;
  17. for (int i = 0; i < sizeof(num) / sizeof(int); i++)
  18. {
  19. int temp = num[i];
  20. while (temp % 2 == 0)
  21. {
  22. count_2++;
  23. temp /= 2;
  24. }
  25. while (temp % 5 == 0)
  26. {
  27. count_5++;
  28. temp /= 5;
  29. }
  30. }
  31. cout << min(count_2, count_5) << endl;
  32. return 0;
  33. }

答案:31 

测试次数

思路:

这里有两种解法 动态规划 和 手算 后一种方法比较好理解就不做解释 主要来解决一下动态规划

首先要理解一下dp[i][j] i表示手机数 j表示楼层数 dp[][]就表示有i部手机j层楼的情况下 最坏运气下需要测试的次数

我们先假设不采取最佳策略 即没一个j层的楼房 我们都要摔j次 但是当手机只有一部的情况时 这其实就是最佳策略,那么我们就可以逐渐往上拓展

假设我们已经把 i-1部手机对于所有楼层的次数已经找出,现在我们来求有i部手机时的测试次数

为此我们需要遍历 当前之前的楼层k(1~j-1)假设在k层摔坏 我们就选取i-1部手机对于k-1层楼房的最坏情况dp[i-1][k-1]+1

假如在k层没有摔坏 那么我们就可以选取i部手机对于剩下j-k层的最坏情况 dp[i][j-k]+1

由于是最坏情况 我们需要在两者之间取最大值,但我们又是采取的最佳策略 所以对于之前的非最佳策略 我们需要取最小值,即:

dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1);

代码

  1. #include<iostream>
  2. using namespace std;
  3. int dp[5][1007];
  4. int main()
  5. {
  6. ios::sync_with_stdio(false);
  7. for (int i = 1; i <= 3; i++)
  8. for (int j = 1; j <= 1000; j++)
  9. dp[i][j] = j;
  10. for (int i = 1; i <= 1000; i++)
  11. for (int j = 2; j <= 3; j++) {
  12. for (int k = 1; k < i; k++)
  13. dp[j][i] = min(dp[j][i], max(dp[j - 1][k - 1], dp[j][i - k]) + 1);
  14. }
  15. cout << dp[3][1000] << endl;
  16. return 0;
  17. }

答案:19 

快速排序

以下代码可以从数组a[]中找出第k小的元素。

它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。

请仔细阅读分析源码,填写划线部分缺失的内容。

  1. #include <stdio.h>
  2. int quick_select(int a[], int l, int r, int k) {
  3. int p = rand() % (r - l + 1) + l;
  4. int x = a[p];
  5. {int t = a[p]; a[p] = a[r]; a[r] = t;}
  6. int i = l, j = r;
  7. while(i < j) {
  8. while(i < j && a[i] < x) i++;
  9. if(i < j) {
  10. a[j] = a[i];
  11. j--;
  12. }
  13. while(i < j && a[j] > x) j--;
  14. if(i < j) {
  15. a[i] = a[j];
  16. i++;
  17. }
  18. }
  19. a[i] = x;
  20. p = i;
  21. if(i - l + 1 == k) return a[i];
  22. if(i - l + 1 < k) return quick_select( _____________________________ ); //填空
  23. else return quick_select(a, l, i - 1, k);
  24. }
  25. int main()
  26. {
  27. int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
  28. printf("%d\n", quick_select(a, 0, 14, 5));
  29. return 0;
  30. }

思路:代码的大概意思就是先随机生成一个数,把比这个小的都放在它的左边,比它大的数都放在右边,这个数若是是第k小的就返回,若是小于k就再向右半部分,此时就不是第k小的了,不然就向左边去找第k小的数.

答案:(a,i+1,r,k-(i-l+1)); 

递增三元组

 

思路:对A C数组排序后,分别二分A,C数组,这样我们就会得到A中小于B[ j ]的数和C中大于B[ j ]的数,由于 A C 是有序的,那么A数组二分数之前的数和C数组二分数之后的数也满足,两数组满足数相乘即可,这样我们边找到了包含B[ j ]的所有递增三元组的数量,遍历数组B即可。这种方法的时间复杂度为O ( n ( l o g n ) ) .

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. //4
  5. //1 3 4 5
  6. //1 2 2 2
  7. //2 3 3 4
  8. int a[100010];
  9. int b[100010];
  10. int c[100010];
  11. int n;
  12. long long ans = 0;
  13. int main(){
  14. //输入数据
  15. cin>>n;
  16. for(int i=1;i<=n;i++){
  17. cin>>a[i];
  18. }
  19. for(int i=1;i<=n;i++){
  20. cin>>b[i];
  21. }
  22. for(int i=1;i<=n;i++){
  23. cin>>c[i];
  24. }
  25. //排序
  26. sort(a+1,a+n+1);
  27. sort(b+1,b+n+1);
  28. sort(c+1,c+n+1);
  29. //定义两个指针(下标)
  30. int j = 1;
  31. int k = 1;
  32. //以b为中间值 在a数组 c数组中查找
  33. for(int i=1;i<=n;i++){
  34. while(j<=n && a[j] < b[i]) j++; //在a数组中查找第一个大于等于b[i]的数
  35. while(k<=n && c[k] <= b[i]) k++; //在c数组中查找第一个大于b[i]的数
  36. ans += (long long)(j-1) * (n-k+1); //计算公式 可以自己举例推导出来
  37. }
  38. cout<<ans<<endl;
  39. }

螺旋折线 

 

思路:我们可以将其看成有边长为2、4、6、8......的正方形组成的,所以可以根据给出的X、Y值求max(X,Y)来判断这个点是属于哪个正方形里面的,再从X,Y的位置判断是位于正方形的上下左右那一条边的来求dis(X,Y)

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cmath>
  5. #include<algorithm>
  6. using namespace std;
  7. typedef long long LL;
  8. const int Max_n=100005;
  9. int f(int x,int y,int n){
  10. if(x==-n){
  11. if(y==-n)
  12. return 8*n;//n*2*4;
  13. return y+n;//1+(y+n-1);
  14. }
  15. if(y==n){
  16. return 3*n+x;//1+2*n-1+x+n;
  17. }
  18. if(x==n){
  19. return 5*n-y;//1+2*n-1+2*n+n-y;
  20. }
  21. if(y==-n){
  22. return 7*n-x;//1+2*n-1+2*n+2*n+n-x;
  23. }
  24. }
  25. int main(){
  26. int x,y;
  27. scanf("%d%d",&x,&y);
  28. int n=max(abs(x),abs(y));
  29. LL ans=1LL*n*(n-1)*4+f(x,y,n);
  30. printf("%lld\n",ans);
  31. return 0;
  32. }

 日志统计

 

思路:这个在代码里标记得很清楚 

代码

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <set>
  5. #include <map>
  6. using namespace std;
  7. int N,D,K,ans;
  8. //存储日志
  9. struct log{
  10. int id,time;
  11. };
  12. //对id进行升序排序
  13. bool cmp(log a,log b)
  14. {
  15. return a.time < b.time;
  16. }
  17. int main()
  18. {
  19. //快读配置
  20. std::ios::sync_with_stdio(0);
  21. //读取规模
  22. cin>>N>>D>>K;
  23. //存储多个日志并排序
  24. vector<log> logs(N);
  25. for(int i = 0;i<N;++i)
  26. {
  27. cin>>logs[i].time>>logs[i].id;
  28. }
  29. sort(logs.begin(),logs.end(),cmp);
  30. //记录答案
  31. set<int> ans;
  32. //记录id出现的次数
  33. map<int,int>cnt;
  34. int j = 0;//哨兵
  35. for(int i = 0;i<N;++i)
  36. {
  37. while(j<N&&logs[j].time-logs[i].time<D)
  38. {
  39. cnt[logs[j].id]++;
  40. if(cnt[logs[j].id]>=K)ans.insert(logs[j].id);
  41. j++;
  42. }
  43. cnt[logs[i].id]--;
  44. }
  45. for(set<int>::iterator i = ans.begin();i !=ans.end();i++)cout<<*i<<endl;
  46. return 0;
  47. }

全球变暖 

 

思路:可以这样求解,通过广度优先遍历BFS查找地图,查找过程中记录某连通陆地中临近水的陆地数量和连通块里的陆地数量,如果二者相同那么该连通陆地会被淹没

  1. #include <iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<queue>
  6. using namespace std;
  7. int N,ans;
  8. char F_area[1000][1000];
  9. int M_area[1000][1000];
  10. //坐标的四周
  11. int Lx[] = {0,0,1,-1};
  12. int Ly[] = {1,-1,0,0};
  13. //存储坐标
  14. struct Point{
  15. int x,y;
  16. };
  17. void BFS(int i,int j)
  18. {
  19. M_area[i][j] = 1;//标记该点已读
  20. queue<Point> q;
  21. q.push({i,j});//将当前坐标存入队列
  22. int cn1 = 0,cn2 = 0;//记录当前连通陆地的数量以及和水相邻的数量
  23. while(!q.empty())
  24. {
  25. Point first = q.front();
  26. q.pop();
  27. cn1 ++;//数量
  28. bool swed = false;//标记该坐标四周是否有水
  29. for(int k = 0;k<4;++k)//查找四周
  30. {
  31. int x = first.x + Lx[k];
  32. int y = first.y + Ly[k];
  33. if(0<=x&&x<N&&0<=y&&y<N&&F_area[x][y]=='.')swed = true;
  34. if(0<=x&&x<N&&0<=y&&y<N&&F_area[x][y]=='#'&&M_area[x][y] ==0)
  35. {
  36. q.push({x,y});//与某陆地坐标相邻的陆地进入队列
  37. M_area[x][y] = 1;
  38. }
  39. }
  40. if (swed)cn2++; //如果该坐标四周有水,则记录到临近水的陆地数量中
  41. }
  42. if(cn1 == cn2)ans++;//某坐标点开始找,找完所有陆地
  43. }
  44. int main()
  45. {
  46. //快读配置
  47. std::ios::sync_with_stdio(0);
  48. //读取规模
  49. cin>>N;
  50. //读取地图
  51. for(int i = 0;i<N;++i)
  52. {
  53. for(int j = 0;j<N;++j)
  54. {
  55. cin>>F_area[i][j];
  56. }
  57. }
  58. //进行广搜查找
  59. for(int i = 0;i<N;++i)
  60. {
  61. for(int j = 0;j<N;++j)
  62. {
  63. if(M_area[i][j]==0&& F_area[i][j]=='#')//如果这个坐标是陆地且没有被访问过
  64. {
  65. BFS(i,j);
  66. }
  67. }
  68. }
  69. cout<<ans<<endl;;
  70. return 0;
  71. }

乘积最大 

思路:家人们肝不动了,拿大佬的代码,在这里给大家参考吧,共同学习

博客:蓝桥杯-历届试题-乘积最大_柯基吹泡泡的博客-CSDN博客_乘积最大蓝桥杯

代码

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N=1e5+10;
  5. long long int st[N];
  6. int main()
  7. {
  8. int n,k;
  9. cin>>n>>k;
  10. int ft=0;
  11. for(int i=0;i<n;i++)
  12. {
  13. cin>>st[i];
  14. if(st[i]<0)ft++;
  15. }
  16. sort(st,st+n);
  17. long long int ans=1;
  18. if(k%2!=0&&ft==n)
  19. {
  20. for(int i=0;i<k;i++)
  21. {
  22. ans=ans*st[n-1-i]%1000000009;
  23. ans=ans%1000000009;
  24. }
  25. cout<<ans%1000000009;
  26. return 0;
  27. }
  28. if(k%2!=0)
  29. {
  30. ans=st[n-1];
  31. k--;
  32. n--;
  33. }
  34. int tt=0;
  35. int u=0,v=n-1;
  36. while(tt<k)
  37. {
  38. if(st[u]*st[u+1]>=st[v]*st[v-1])
  39. {
  40. long long pp=st[u]*st[u+1]%1000000009;
  41. ans=ans*pp%1000000009;
  42. ans=ans%1000000009;
  43. u+=2;
  44. tt+=2;
  45. }
  46. else
  47. {
  48. long long oo=st[v]*st[v-1]%1000000009;
  49. ans=ans*oo%1000000009;
  50. ans=ans%1000000009;
  51. v=v-2;
  52. tt=tt+2;
  53. }
  54. }
  55. cout<<ans%1000000009;
  56. }

           好啦,今天就到这里,学累了吧xdm,上图缓解视觉疲劳

 

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览45269 人正在系统学习中