【蓝桥杯】2022年十三届省赛大学B组真题(c/c++)1.扫雷2.九进制转十进制3.顺子日期4.刷题统计5.修剪灌木6.X 进制减法7.统计子矩阵8.积木画9.李白打酒加强版10.砍竹子

目录

1.题目:扫雷

题目描述

输入描述

输出描述

输入输出样例

示例 1

题解:

2.题目:九进制转十进制

问题描述

运行限制

题解:

3.题目:顺子日期

问题描述

运行限制

题解:

4.题目:刷题统计

问题描述

输入格式

输出格式

样例输入

样例输出

评测用例规模与约定

题解:

5.题目:修剪灌木

问题描述

输入格式

输出格式

样例输入

样例输出

评测用例规模与约定

运行限制

题解:

6.题目:X 进制减法

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

评测用例规模与约定

运行限制

题解:(不是特别懂)

7.题目:统计子矩阵

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

评测用例规模与约定

运行限制

题解:(前缀和+双指针)

8.题目:积木画

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

评测用例规模与约定

题解:

思路(动态规划):

代码:

9.题目:李白打酒加强版

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

评测用例规模与约定

运行限制

题解(动态规划):

10.题目:砍竹子

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

评测用例规模与约定

运行限制

题解:


1.题目:扫雷

题目描述

在一个 nn 行 mm 列的方格图上有一些位置有地雷,另外一些位置为空。

请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。

输入描述

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

第 22行到第 n+1 行每行包含 m个整数,相邻整数之间用一个空格分隔。如果对应的整数为 0,表示这一格没有地雷。如果对应的整数为 1,表示这一格有地雷。

其中,1≤n,m≤100 分钟后还是在当天。

输出描述

输出 n 行,每行 m 个整数,相邻整数之间用空格分隔。

对于没有地雷的方格,输出这格周围的地雷数量。对于有地雷的方格,输出 9。

输入输出样例

示例 1

输入

3 4
0 1 0 0
1 0 1 0
0 0 1 0

输出

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

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

题解:

#include <iostream>
#include<bits/stdc++.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;


int main(int argc, char *argv[])
{
  int n,m;
  scanf("%d %d",&n,&m);
  int a[n+1][m+1]={0};
  int b[n+1][m+1]={0};
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      scanf("%d",&a[i][j]);
    }getchar();
  }
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      if(a[i][j]==1){
        b[i][j]=9;
      }else{
        for(int q=i-1;q<=i+1;q++){
          for(int p=j-1;p<=j+1;p++){
            if(a[q][p]==1){
              b[i][j]++;
            }
          }
        }    
      }
    }
  }
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      if(j<m){
        printf("%d ",b[i][j]);
      }else if(j==m){
        printf("%d\n",b[i][j]);
      }
    }
  }    
  return 0;
}

2.题目:九进制转十进制

问题描述

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

九进制正整数 (2022)9(2022)9​ 转换成十进制等于多少?

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

题解:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  printf("1478");
  return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
  // 请在此输入您的代码
  // 2022
  int a=2*pow(9,3)+0*pow(9,2)+2*pow(9,1)+2*pow(9,0);
  printf("%d",a);
  return 0;
}

3.题目:顺子日期

问题描述

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

小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。小明想知道在整个 2022 年份中,一共有多少个顺子日期?

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

题解:

  //01.20~01.29
  //11.23\10.12\12.30\12.31
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
   int sum=0;
  int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
  int year,month,day;
 
  for(year=2022;year<=2022;year++){

    if((year%4==0&&year%100!=0)||year%400==0){
      months[2]=29;
    }else{
      months[2]=28;
    }
    for(month=1;month<=12;month++){
      int a[5]={0};
      if(month>=10){
         a[1]=month/10;
        a[2]=month%10;
      }else{
        a[1]=0;
        a[2]=month;
      }
      for(day=1;day<=months[month];day++){
        if(day>=10){
           a[3]=day/10;
           a[4]=day%10;
        }
        else{
          a[3]=0;
          a[4]=day;
        }
        if(a[2]-a[1]==1&&a[3]-a[2]==1||a[4]-a[3]==1&&a[3]-a[2]==1){
          sum++;
        }
      }
    }
  }
  printf("%d",sum);
  return 0;
}

4.题目:刷题统计

问题描述

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 aa 道题目, 周六和周日每天做 bb 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 nn 题?

输入格式

输入一行包含三个整数 a,ba,b 和 nn.

输出格式

输出一个整数代表天数。

样例输入

10 20 99

样例输出

8

评测用例规模与约定

对于 50%50% 的评测用例, 1≤a,b,n≤1061≤a,b,n≤106.

对于 100%100% 的评测用例, 1≤a,b,n≤10181≤a,b,n≤1018.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

题解:

1.(一开始我写的只能满足样例的60%)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int a,b,n;
  scanf("%d %d %d",&a,&b,&n);
  int m=n;
  int z=0;
  while(n>=0){
    for(int i=1;i<=5;i++){
      n=n-a;
      z++;
      if(n<=0){
        printf("%d",z);
        return 0;
      } 
    }
    for(int i=1;i<=2;i++){
      n=n-b;
      z++;
      if(n<=0){
        printf("%d",z);
        return 0;
      } 
    }
  }
  
}

2.比较简洁的思路,先求周数,在求天数

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  long long int a,b,n;
  long long int week,rem=0,sum;
  scanf("%lld %lld %lld",&a,&b,&n);
  week=5*a+2*b;
  sum=n/week*7;
  rem=n%week;
  for(int i=1;i<=7;i++)
  {
    if(rem<=0)break;
    if(i<=5)rem-=a;
    else rem-=b;
    sum++;
  }
  printf("%lld",sum);
  return 0;
}

5.题目:修剪灌木

问题描述

爱丽丝要完成一项修剪灌木的工作。

有 NN 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晩会修剪一棵灌 木, 让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后, 她会调转方向, 下一天开 始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。

灌木每天从早上到傍晩会长高 1 厘米, 而其余时间不会长高。在第一天的 早晨, 所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

输入格式

一个正整数 NN, 含义如题面所述。

输出格式

输出 NN 行, 每行一个整数, 第 ii 行表示从左到右第 ii 棵树最高能长到多高。

样例输入

3

样例输出

4
2
4

评测用例规模与约定

对于 30%30% 的数据, N≤10N≤10.

对于 100%100% 的数据, 1<N≤100001<N≤10000.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

题解:

方法如下,①,先想像一下,植物A是那一排植物中的某一个植物,题目既然 说了,不割就会一直长高,但一旦一割就变成0,即找出被割的前一天即是最高高度。那么很容易就知道,植物A最高时是多少,即,假定一个时间段s,割完植物A去割下一个植物开始计时,一直到下一个又该割植物A时结束计时,此时的植物A高度最高//②,所以,植物A高度最高时,生长的时间s是最长的,但题目没说时间,那也没事,因为收割速度恒定,一天一割,那么根据速度公式,找出长度最长,即找到了时间最长,即最高高度就有了。所以就得找植物A是距离哪个端点更远了,毕竟他得从端点绕回来,假如左端点离植物A远,那就在从右向左割到植物A左边的植物时开始计时,再割回到植物A时结束计时,此时长度是最长的,时间最长的,那么在此时间段内植物A生长的高度也是最高的高度。③,还不懂?没事,给你草图一下 : /* XXBAXX */ 这是五个植物一排,植物A也在其中,因为植物A离左端点远,所以从右向左割到植物B时记起,再次割到植物A时结束(端点割两次),那么,长度是6,时间是6,那么A的最高高度,一天1厘米,那就是6厘米。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int n;
  int m;
  scanf("%d",&n);
  int left,right;
  int max[n];
  for(int i=0;i<n;i++){
    right=n-i-1;
    left=i;
    if(left<=right){
      max[i]=2*right;
    }else{
      max[i]=2*left;
    }
  }
  for(int i=0;i<n;i++){
    printf("%d\n",max[i]);
  }
  return 0;
}

6.题目:X 进制减法

问题描述

进制规定了数字在数位上逢几进一。

X 进制是一种很神奇的进制, 因为其每一数位的进制并不固定!例如说某 种 X 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 X 进制数 321 转换为十进制数为 65 。

现在有两个 X 进制表示的整数 A 和 B, 但是其具体每一数位的进制还不确 定, 只知道 A 和 B 是同一进制规则, 且每一数位最高为 N 进制, 最低为二进 制。请你算出 A−B 的结果最小可能是多少。

请注意, 你需要保证 A 和 B 在 X 进制下都是合法的, 即每一数位上的数 字要小于其进制。

输入格式

第一行一个正整数 N, 含义如题面所述。

第二行一个正整数 Ma​, 表示 X 进制数 A 的位数。

第三行 Ma​ 个用空格分开的整数, 表示 X 进制数 A 按从高位到低位顺序各 个数位上的数字在十进制下的表示。

第四行一个正整数 Mb​, 表示 X 进制数 B 的位数。

第五行 Mbb 个用空格分开的整数, 表示 X 进制数 B 按从高位到低位顺序各 个数位上的数字在十进制下的表示。

请注意, 输入中的所有数字都是十进制的。

输出格式

输出一行一个整数, 表示 XX 进制数 A−B 的结果的最小可能值转换为十进 制后再模 1000000007 的结果。

样例输入

11
3
10 4 0
3
1 2 0

样例输出

94

样例说明

当进制为: 最低位 2 进制, 第二数位 5 进制, 第三数位 11 进制时, 减法 得到的差最小。此时 A 在十进制下是 108,B 在十进制下是 14 , 差值是 94。

评测用例规模与约定

对于 30% 的数据, N≤10;Ma,Mb≤8.

对于 100% 的数据, 2≤N≤1000;1≤Ma,Mb≤100000;A≥B.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

题解:(不是特别懂)

#include <stdio.h>
#include <stdlib.h>
int a[100001],b[100001],c[100001];

int bi(int a,int b)
{
  if(a>b) return a;
  else return b;
}

int main(int argc, char *argv[])
{
  int n;
  scanf("%d",&n); 
  int na,nb,nc;
  scanf("%d",&na);
  for(int i=na-1;i>=0;i--) scanf("%d",&a[i]);
  scanf("%d",&nb);
  for(int i=nb-1;i>=0;i--) scanf("%d",&b[i]);

  nc=bi(na,nb);
  for(int i=nc-1;i>=0;i--)
  {
    c[i]=bi(bi(a[i],b[i])+1,2);
  }
  long long A=0,B=0,m=1000000007;
  for(int i=nc-1;i>=0;i--)
  {
    A=(A*c[i]+a[i])%m;
    B=(B*c[i]+b[i])%m;
  }
  A=(A-B+m)%m;
  printf("%lld",A);
  return 0;
}

7.题目:统计子矩阵

问题描述

给定一个 N×MN×M 的矩阵 AA, 请你统计有多少个子矩阵 (最小 1×11×1, 最大 N×M)N×M) 满足子矩阵中所有数的和不超过给定的整数 KK ?

输入格式

第一行包含三个整数 N,MN,M 和 KK.

之后 NN 行每行包含 MM 个整数, 代表矩阵 AA.

输出格式

一个整数代表答案。

样例输入

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

样例输出

19

样例说明

满足条件的子矩阵一共有 19 , 包含:

大小为 1×11×1 的有 10 个。

大小为 1×21×2 的有 3 个。

大小为 1×31×3 的有 2 个。

大小为 1×41×4 的有 1 个。

大小为 2×12×1 的有 3 个。

评测用例规模与约定

对于 30%30% 的数据, N,M≤20N,M≤20.

对于 70%70% 的数据, N,M≤100N,M≤100.

对于 100%100% 的数据, 1≤N,M≤500;0≤Aij≤1000;1≤K≤2500000001≤N,M≤500;0≤Aij​≤1000;1≤K≤250000000.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

题解:(前缀和+双指针)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int n, m, k = 0; 
  long long res = 0;
	scanf("%d %d %d", &n, &m, &k);
	int arr[n+1][m+1];
	for (int i = 1; i <= n; i++)
	{
	    for (int j = 1; j <= m; j++)
	    {
	        scanf("%d", &arr[i][j]);
	        arr[i][j] += arr[i-1][j];//算出每一列的前缀和
	    }
	}
	for (int i = 1; i <= n; i++)
	{
	    for (int j = i; j <= n; j++)
	    {
	        for (int l = 1, r = 1,sum=0; r <= m; r++)
	        {
	            sum += arr[j][r] - arr[i- 1][r];
	            while (sum > k)
	            {
	                sum -= arr[j][l] - arr[i - 1][l];
	                l++;
	            }
	            res += r - l + 1;
	
	        }
	    }
	
	}
	 printf("%lld", res);
	 return 0;
}

8.题目:积木画

问题描述

小明最近迷上了积木画, 有这么两种类型的积木, 分别为 II 型(大小为 2 个单位面积) 和 LL 型 (大小为 3 个单位面积):

图片描述

同时, 小明有一块面积大小为 2×N2×N 的画布, 画布由 2×N2×N 个 1×11×1 区域构 成。小明需要用以上两种积木将画布拼满, 他想知道总共有多少种不同的方式? 积木可以任意旋转, 且画布的方向固定。

输入格式

输入一个整数 NN,表示画布大小。

输出格式

输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值。

样例输入

3

样例输出

5

样例说明

五种情况如下图所示,颜色只是为了标识不同的积木:

图片描述

评测用例规模与约定

对于所有测试用例,1≤N≤100000001≤N≤10000000.

运行限制

  • 最大运行时间:3s
  • 最大运行内存: 512M

题解:

思路(动态规划):

1.分析:

这道题是一道 dp 题,nn 的范围高达 107107,所以时间复杂度只有一种:O(n)O(n)。

我们可以这样想,一个积木放上去后,可能会出现三种情况:第一行比第二行多出一个积木;两行积木数相等;第二行比第一行多出一个积木。

这时候有同学可能会问:为什么最多就多出一个积木呢?

因为最后的答案一定是两行积木数相等,如果两行差的多了,就不能用 L 型积木填补。只用 I 型积木填补的话,只能横着填补,我们完全可以在之前相差不超过 11 时就用 I 型积木横着填补。

所以,状态定义就是:int f[10000005][3]注意:这里的 f[i][0]f[i][2] 表示更长的一列的长度为 ii。


接下来就是动态转移方程了。

如果第一行比第二行多出一个积木,也就是状态 f[i][0]。此时我们可以用一个 I 型积木在第一行横向填补,这样在填补前第二行就会多出一个积木,也就是 f[i-1][2];也可以用一个 L 型积木填补第 ii 列和 i−1i−1 列,这样填补前两行积木数就相等,也就是 f[i-2][1]

如果第二行比第一行多出一个积木,也就是状态 f[i][2]。此时与上一种情况类似,也是两种方案,分别是用一个 I 型积木在第二行横向填补和用一个 L 型积木进行填补。分别是 f[i-1][0]f[i-2][1]

最后,也是最复杂的一种情况,就是两行积木数相等,即状态 f[i][1]。此时有 44 种情况。我们可以用两个 I 型积木横向填补第 ii 列和第 i−1i−1 列,就是 f[i-2][1];可以用一个 I 型积木纵向填补第 ii 列,也就是 f[i-1][1];可以用一个 L 型积木填补第 ii 列和第 i−1i−1 列的第一行,也就是 f[i-1][2];还可以用一个 L 型积木填补第 ii 列和第 i−1i−1 列的第二行,也就是 f[i-1][0]

温馨提示:这一部分可能不是很好懂,同学们可以画个图帮助理解。


初始化就很简单了,即一列都没有,两行积木数都为 00 也就是积木数相等的情况有 11 种,也就是 f[0][1]=1

输出也很简单,就是前 nn 列,两行积木数相等的情况数。

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,f[10000005][3];
int main(){
	cin>>n;
	f[0][1]=1;
	for(int i=1;i<=n;i++){
		f[i][0]=(f[i-2][1]+f[i-1][2])%mod;
		f[i][1]=((f[i-2][1]+f[i-1][1])%mod+(f[i-1][0]+f[i-1][2])%mod)%mod;//两两相加就取模,防止超出int
		f[i][2]=(f[i-2][1]+f[i-1][0])%mod;
	}
	cout<<f[n][1];
	return 0;
}

9.题目:李白打酒加强版

问题描述

话说大诗人李白, 一生好饮。幸好他从不开车。

一天, 他提着酒显, 从家里出来, 酒显中有酒 2 斗。他边走边唱:

无事街上走,提显去打酒。 逢店加一倍, 遇花喝一斗。

这一路上, 他一共遇到店 NN 次, 遇到花 MM 次。已知最后一次遇到的是花, 他正好把酒喝光了。

请你计算李白这一路遇到店和花的顺序, 有多少种不同的可能?

注意: 显里没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。

输入格式

第一行包含两个整数 NN 和 MM.

输出格式

输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果.

样例输入

5 10

样例输出

14

样例说明

如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:

010101101000000

010110010010000

011000110010000

100010110010000

011001000110000

100011000110000

100100010110000

010110100000100

011001001000100

100011001000100

100100011000100

011010000010100

100100100010100

101000001010100

评测用例规模与约定

对于 40%40% 的评测用例: 1≤N,M≤101≤N,M≤10 。

对于 100%100% 的评测用例: 1≤N,M≤1001≤N,M≤100 。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

题解(动态规划):

#include<stdio.h>
const int N=105,mod=1000000007;
int main()
{
    int f[N][N][N]; 
    int n,m,i,j,k;  //n是酒店,m是花店,k是酒的数量 
    scanf("%d %d",&n,&m);
    f[0][0][2]=1;
    for(i=0;i<=n;i++){
        for(j=0;j<=m;j++){
            for(k=0;k<=m;k++){
                if(i>=1&&k%2==0){   //最后遇到的是酒店 
                    f[i][j][k]=(f[i][j][k]+f[i-1][j][k/2])%mod;
                }
                if(j>=1){  //最后遇到的是花店 
                    f[i][j][k]=(f[i][j][k]+f[i][j-1][k+1])%mod;
                }
            }
        }
    }
    printf("%d",f[n][m-1][1]);
    return 0;
}

10.题目:砍竹子

问题描述

这天, 小明在砍竹子, 他面前有 nn 棵竹子排成一排, 一开始第 ii 棵竹子的 高度为 hihi​.

他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为 HH, 那么

用一次魔法可以 把这一段竹子的高度都变为 ⌊⌊H2⌋+1⌋⌊⌊2H​⌋+1

​⌋, 其中 ⌊x⌋⌊x⌋ 表示对 xx 向下取整。小明想 知道他最少使用多少次魔法可

让所有的竹子的高度都变为 1 。

输入格式

第一行为一个正整数 nn, 表示竹子的棵数。

第二行共 nn 个空格分开的正整数 hihi​, 表示每棵竹子的高度。

输出格式

一个整数表示答案。

样例输入

6
2 1 4 2 6 7

样例输出

5

样例说明

其中一种方案:

21426214267 →214262→214222→211222→111222→111111​→214262→214222→211222→111222→111111​ 共需要 5 步完成

评测用例规模与约定

对于 20%20% 的数据, 保证 n≤1000,hi≤106n≤1000,hi​≤106 。 对于 100%100% 的数据, 保证 n≤2×105,hi≤1018n≤2×105,hi​≤1018 。

运行限制

  • 最大运行时间:2s
  • 最大运行内存: 256M

题解:

思路是先把每个竹子砍到1,每砍一次次数+1,再回来看第i和第i+1个竹子在砍的时候是否有出现相同的高度,每出现一次次数-1。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

long long h[200001][8];

long long sum(long long n)
{
  long long res;
  res=sqrtl(n/2+1);
  return res;
}

int main(int argc, char *argv[])
{
  long long n,i,j,res=0,k;
  scanf("%lld",&n);
  for(i=0;i<n;i++){
    scanf("%lld",&h[i][0]);
    for(j=1;h[i][j-1]>1;j++){
      h[i][j]=sum(h[i][j-1]);
      res++;
    }
  }
  for(i=0;i<n-1;i++){
    for(j=0;h[i][j]!=1;j++){
      for(k=0;h[i+1][k]!=1;k++){
          if(h[i][j]==h[i+1][k]){
              res--;
              break;
        }
      }
    }
  }
  printf("%lld",res);
  return 0;
}

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值