当前位置:   article > 正文

蓝桥杯专题之思维篇_小蓝要在路边划分停车位。   他将路边可停车的区域划分为 l 个整数小块,编号 1

小蓝要在路边划分停车位。   他将路边可停车的区域划分为 l 个整数小块,编号 1

题目列表:

2014年:蚂蚁感冒

2016年:交换瓶子

2018年:乘积最大

2019年:后缀表达式

2022年第一次模拟赛:停车位

1.蚂蚁感冒

题目描述
长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。 这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。 请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
输入
第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。

接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。
输出
要求输出1个整数,表示最后感冒蚂蚁的数目。
样例输入
3
5 -2 8
5
-10 8 -20 12 25
样例输出
1
3

分析:

当两只蚂蚁碰面时,他们会同时掉头往相反的方向爬行。

其实我们不要将蚂蚁区别化,哦,这只蚂蚁怎么走,那只蚂蚁怎么走,完全不需要这样,你这样一只一只的看,假如给你100只蚂蚁,你难道还要把他们的运动轨迹一一记录下来吗!!

从左边来的蚂蚁和从右边来的蚂蚁碰面后掉头,掉头以后,还是有一只蚂蚁在向左走,有一只蚂蚁在向右走,所以我们完全可以当成什么都没有发生,从左边来的蚂蚁仍然向右走,从右边来的蚂蚁仍然向左走,两只中只要有一只感冒了,两只都感冒

如果感冒的蚂蚁向右走,判断有多少只蚂蚁在它的右边并且向左走,这些蚂蚁是要被传染的,还有在他身后也在向右走的蚂蚁,他们也是要被传染的

如果感冒的蚂蚁向左走,判断有多少只蚂蚁在它的左边并且向右走,这些蚂蚁是要被传染的,还有在他身后也在向左走的蚂蚁,他们也是要被传染的

代码:

  1. #include<iostream>
  2. #include<cmath>
  3. using namespace std;
  4. int main(){
  5. int n;
  6. cin >> n;
  7. int cnt = 1;
  8. int first;
  9. cin >> first;
  10. int k;
  11. for(int i = 0;i < n-1;i++){
  12. cin >> k;
  13. if(first > 0){
  14. if((abs(k) > first && k < 0) || (k > 0 && k < first)){
  15. cnt++;
  16. }
  17. }else{
  18. if((abs(k) < abs(first) && k > 0) || (k < 0 && abs(k) > abs(first))){
  19. cnt++;
  20. }
  21. }
  22. }
  23. cout << cnt;
  24. return 0;
  25. }

2.交换瓶子

题目描述

有N个瓶子,编号 1 ~ N,放在架子上。

比如有5个瓶子:
2 1 3 5 4

要求每次拿起2个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5

对于这么简单的情况,显然,至少需要交换2次就可以复位。

如果瓶子更多呢?你可以通过编程来解决。

输入格式为两行:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。

输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。

例如,输入
5
3 1 2 5 4

程序应该输出
3

再例如,输入
5
5 4 3 2 1

程序应该输出
2

分析:

这道题我刚写的时候想到了逆序对,正一遍求逆序对再逆过来再求一遍逆序对,两遍地结果相加正好是每个数需要移动的次数,但是这个移动是怎么个移法,他是每次只能交换相邻两个元素;

例:

        3   1   2   5   4

正: 0   1   1   0   1

+

反: 2   0   0   1   0

=      2   1   1   1   1

但是这道题它可以随便交换,所以这种求法在这里就不适用了

但是,我们可以发现:

5    1    4    2    3

从第一个数开始移,5不在正确的位置,需要交换;交换后,3    1    4    2    5

指针先不着急往后移,要检查交换过来的数是否也在正确的位置上,如果不在,继续交换(这有点 像快排的思想,右边的数交换过来后不着急向后走,再检查换过来的这个数)

3不在正确的位置,需要交换;交换后,4    1    3    2    5

4不在正确的位置,需要交换,交换后,2    1    3    4    5

2不在正确的位置,需要交换,交换后,1    2    3    4    5

最终,所有的数都回到了自己的位置

代码:

  1. #include<iostream>
  2. using namespace std;
  3. const int MAX_N = 10010;
  4. int N;
  5. int a[MAX_N];
  6. int main(){
  7. cin >> N;
  8. for(int i = 1;i <= N;i++){
  9. cin >> a[i];
  10. }
  11. int cnt = 0;
  12. for(int i = 1;i <= N;){
  13. if(i != a[i]){
  14. int temp = a[i];
  15. a[i] = a[temp];
  16. a[temp] = temp;
  17. cnt++;
  18. }else{
  19. i++;
  20. }
  21. }
  22. cout << cnt;
  23. return 0;
  24. }

3.乘积最大

【问题描述】

给定 N 个整数 A1,A2, …, AN。

请你从中选出 K 个数,使其乘积最大。

请你求出最大的乘积,由于乘积可能超出整型范围,你只需输出乘积除以 1000000009 的余数。

注意,如果 X<0, 我们定义 X 除以 1000000009 的余数是负(−X)除以 1000000009的余数,即:0−((0−x)%1000000009)

【输入格式】
第一行包含两个整数 N 和 K。
以下 N 行每行一个整数 Ai。

【输出格式】
输出一个整数,表示答案。

【输入样例1】

5 3

-100000

-10000

2

100000

10000

【输出样例1】

999100009

【输入样例2】

5 3

-100000

-100000

-2

-100000

-100000

【输出样例2】

-999999829

【评测用例规模与约定】
1 ≤ K ≤ N ≤ 1e5
−1e5 ≤ Ai ≤ 1e5

分析:

1.如果正数(包括0)的个数大于等于k,那么就从正数中从大到小选K个数相乘

2.如果正数(包括0)的个数小于k(设正数的个数为g)

        如果k-g=偶数,就从负数中从小到大选k-g个数,再与g个正数相乘

        如果k-g=奇数,就从负数中从大到小选k-g个数,再与g个正数相乘

代码(只过了40%的数据,自己也不知道问题出在哪,如果有大佬路过,可以帮我指出来吗,感谢^^):

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int MAX_N = 1e5+10;
  5. const long long MOD = 1e9+9;
  6. int N,K;
  7. int a[MAX_N],b[MAX_N];
  8. long long ans = 1;
  9. bool mycmp(int a,int b){
  10. return a > b;
  11. }
  12. int main(){
  13. cin >> N >> K;
  14. int m,j = 0,l = 0;
  15. for(int i = 0;i < N;i++){
  16. cin >> m;
  17. if(a[i] >= 0){
  18. a[j++] = m;
  19. }else{
  20. b[l++] = m;
  21. }
  22. }
  23. if(j >= K){
  24. sort(a,a+j,mycmp);
  25. for(int i = 0;i < K;i++){
  26. ans *= a[i];
  27. }
  28. cout << ans % MOD;
  29. }else{
  30. for(int i = 0;i < j;i++){
  31. ans *= a[i];
  32. }
  33. if((K-j) % 2 ==0){
  34. sort(b,b+l);
  35. for(int i = 0;i < K-j;i++){
  36. ans *= b[i];
  37. }
  38. cout << ans%MOD;
  39. }else{
  40. sort(b,b+l,mycmp);
  41. for(int i = 0;i < K-j;i++){
  42. ans *= b[i];
  43. }
  44. cout << -((0-ans)%MOD);
  45. }
  46. }
  47. return 0;
  48. }

4.后缀表达式

 题目描述
给定N 个加号、M 个减号以及N + M + 1 个整数A1,A2,…,AN+M+1
小明想知道在所有由这N 个加号、M 个减号以及N + M +1 个整数凑出的合法的后缀表达式中,结果最大的是哪一个?
请你输出这个最大的结果。
例如使用1 2 3 + -,则“2 3 + 1 -” 这个后缀表达式结果是4,是最大的。

输入
第一行包含两个整数N 和M。
第二行包含N + M + 1 个整数A1,A2,…,AN+M+1
0<=N,M<=100000,-109<=Ai<=109

输出
输出一个整数,代表答案。

样例输入
1 1
1 2 3

样例输出
4

分析:

如果全是正号,将全部的数相加即可

如果既有正号又有负号,无论负号有多少个,最后都只剩下一个负号

例:假如有一个负号:-a1;两个负号:-(a1-a2)=-a1+a2;三个负号:-(a1-a2-a3) = -a1+a2+a3

所以 如果全为正数,那么那一个负号就减去最小的正数

        如果全为负数或既有正数也有负数,那么那一个负号就减去最小的负数

后缀表达式存在优先级,所以可以任意加括号!!!

意思就是:遇到负数就减,遇到正数就加(举个例子就好理解了^^)

例:3   2   -1    -2   -6      2个加号,3个减号

其后缀表达式为:-(-6 + (-2) + (-1) - 2 - 3)

最后还有个地方需要注意:

        在面对大流量的输入时,尽量使用scanf,会比cin快很多!!!

代码:

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<algorithm>
  4. using namespace std;
  5. int N,M;
  6. const int MAX_N = 2*(1e5+10);
  7. int a[MAX_N];
  8. long long ans;
  9. int main(){
  10. cin >> N >> M;
  11. int k = N+M+1;
  12. for(int i = 0;i < k;i++){
  13. scanf("%d",&a[i]);
  14. }
  15. if(!M){
  16. for(int i = 0;i < k;i++){
  17. ans += a[i];
  18. }
  19. }else{
  20. sort(a,a+k);
  21. ans -= a[0];
  22. for(int i = 1;i < k;i++){
  23. ans += abs(a[i]);
  24. }
  25. }
  26. cout << ans;
  27. return 0;
  28. }

5.停车位

【问题描述】

​ 小蓝要在路边划分停车位。

​ 他将路边可停车的区域划分为 L个整数小块,编号1至L。一个车位需要连续的 K 个小块,停车位不能重叠。有的小块属于井盖、消防通道等区域,不能停车。

​ 请问小蓝最多划分出多少个停车位?

【输入格式】

​ 输入的第一行包含三个整数 L、K、N,分别表示小块数量、一个车位需要的小块数量和不能停车的小块数量,相邻整数之间用一个空格分隔。

​ 第二行包含 N 个整数a[1], a[2], …, a[n],按从小到大的顺序排列,相邻的整数间用空格分隔,表示这些位置不能停车。

【输出格式】

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

【样例输入】

100 10 2
25 91

【样例输出】

8

分析:

这道题的意思就是在那些可以停车的地方可以划分出多少个停车位

例:

一共有100个小块,其中第25个小块和第91个小块不能停车

也就是在第1~24个小块,第26~90个小块,第92~100个小块这三片区域可以切分多少个停车位

代码:

  1. #include<iostream>
  2. using namespace std;
  3. int main(){
  4. int L,K,N;
  5. cin >> L >> K >> N;
  6. int no;
  7. int last = 1;
  8. int ans = 0;
  9. for(int i = 0;i < N;i++){
  10. cin >> no;
  11. ans += (no-last)/10;
  12. last = no+1;
  13. }
  14. cout << ans;
  15. return 0;
  16. }

生活的每一天都很精彩,所以千万不要放弃啊!! 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/606267
推荐阅读
相关标签
  

闽ICP备14008679号