【蓝桥杯】2021年十二届省赛大学B组真题(c、c++)1.空间2.砝码称重3.直线4.时间显示5.括号序列6.杨辉三角形7.双向排序8.路径9.货物摆放10.卡片

目录

1.题目:空间

题解:

2.题目:砝码称重

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

题解:(动态规划)

3.题目:直线

题目描述

题解:

4.题目:时间显示

题目描述

输入描述

输出描述

输入输出样例

示例 1

示例 2

题解:

5.题目:括号序列(未写出)

题目描述

输入描述

输出描述

输入输出样例

6.题目:杨辉三角形

题目描述

输入描述

输出描述

输入输出样例

题解:

7.题目:双向排序

题目描述

输入描述

输出描述

样例说明

题解:(暴力,十个样例只对三个,其他会超时)

8.题目:路径

运行限制

题解:

9.题目:货物摆放

题目描述

答案提交

题解:

10.题目:卡片

问题描述

输入格式

输出格式

样例输入

样例输出

样例说明

题解:


1.题目:空间

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

小蓝准备用 256MB256MB 的内存空间开一个数组,数组的每个元素都是 3232 位 二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问 256MB256MB 的空间可以存储多少个 3232 位二进制整数?

运行限制

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

题解:

#include <stdio.h>

int main(void)
{
  // 1 MB = 1024 KB
  // 1 KB = 1024 Byte
  // 1 Byte = 8 bit
  long long count = 0;
  count = (256 * 1024 * 1024) / 4;
  printf("%lld",count);
  return 0;
}

2.题目:砝码称重

问题描述

你有一架天平和 NN 个砝码,这 NN 个砝码重量依次是 W1,W2,⋅⋅⋅,WNW1​,W2​,⋅⋅⋅,WN​。

请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数 NN。

第二行包含 NN 个整数:W1,W2,W3,⋅⋅⋅,WNW1​,W2​,W3​,⋅⋅⋅,WN​。

输出格式

输出一个整数代表答案。

样例输入

3
1 4 6

样例输出

10

样例说明

能称出的 1010 种重量是:1、2、3、4、5、6、7、9、10、111、2、3、4、5、6、7、9、10、11​。

1=1;1=1;

2=6−4(2=6−4(天平一边放 66,另一边放 4);4);​

3=4−1;3=4−1;

4=4;4=4;

5=6−1;5=6−1;​

6=6;6=6;

7=1+6;7=1+6;

9=4+6−1;9=4+6−1;

10=4+6;10=4+6;

11=1+4+6。11=1+4+6。

评测用例规模与约定

对于 5050的评测用例,1≤N≤151≤N≤15。

对于所有评测用例,1≤N≤100,N1≤N≤100,N​个砝码总重不超过 100000100000。

运行限制

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

题解:(动态规划)

#include<stdio.h>
#include<math.h>
    int d[101][100001]={0};
int main(){
    int n;
    d[0][0]=1;    
    int a[105];
    scanf("%d",&n);
    int su=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        su+=a[i];
        for(int j=0;j<=su;j++)
        if(d[i-1][j]){
            d[i][j]=1;
            d[i][abs(j-a[i])]=1;
            d[i][j+a[i]]=1;
        }
    }
    int sum=0;
    for(int i=1;i<=su;i++){
        if(d[n][i])
        sum++;
    }
    printf("%d",sum);
}

3.题目:直线

题目描述

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

在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。

给定平面上 2 × 3 个整点(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z​,即横坐标 是 00 到 11 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数 的点。这些点一共确定了 11 条不同的直线。

给定平面上 20×2120×21 个整点 (x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z,即横 坐标是 00 到 1919 (包含 00 和 1919) 之间的整数、纵坐标是 00 到 2020 (包含 00 和 2020​) 之 间的整数的点。

请问这些点一共确定了多少条不同的直线。

运行限制

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

题解:

#include <stdio.h>
#include <stdlib.h>
int n = 0;
double ab[100000][2]={{0},{0}};
int fun(int x0,int y0,int x1,int y1)
{
  double a = (y0-y1)*1.0/(x0-x1);
  double b = (x0*y1-x1*y0)*1.0/(x0-x1);
  for(int i=0;i<n;i++)
  {
    if(ab[i][0]==a&&ab[i][1]==b) return 0;
  }
  ab[n][0] = a;
  ab[n][1] = b;
  n++;
  return 1;
}
int main(int argc, char *argv[])
{
  for(int x0=0;x0<20;x0++)
    for(int y0=0;y0<21;y0++)
    {
      for(int x1 = x0+1;x1<20;x1++)
        for(int y1 = y0+1;y1<21;y1++)
          fun(x0,y0,x1,y1);
    }
    printf("%d",2*n+41);

  return 0;
}
//答案是2n+41,其中41是与x轴或y轴平行的直线 其余的直线使用暴力法求解, for(int x0=0;x0<20;x0++) for(int y0=0;y0<21;y0++) {
   //两点确定一条直线,第一个点的所有取值 for(int x1 = x0+1;x1<20;x1++) for(int y1 = y0+1;y1<21;y1++) fun(x0,y0,x1,y1); } 
   //第二个点的所有取值,由于第二个点在第一个点的右上方,确定的直线斜率均为正值,
   //斜率是负数的所有直线都有与之对称的斜率为正数的直线,这也是答案n2的原因。 
   //nt fun(int x0,int y0,int x1,int y1) 参数是两个点 { double a = (y0-y1)1.0/(x0-x1); 
   //求斜率 double b = (x0y1-x1*y0)1.0/(x0-x1); 求截距 for(int i=0;i<n;i++) n是已确定直线的个数,
   //将新求得的直线与已知直线比对 { if(ab[i][0]==a&&ab[i][1]==b) return 0; 
   //如果斜率和截距相同,那么该直线已经被确定过了,下一个点。 } 代码继续执行, ab[n][0] = a; 
   //说明是一条新的直线,存入第n+1条直线的斜率是a。 ab[n][1] = b; 截距是b n++; 直线数目更新 return 1; } printf("%d",2n+41);

4.题目:时间显示

题目描述

小蓝要和朋友合作开发一个时间显示的网站。

在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 19701970 年 11 月 11 日 00:00:0000:00:00 到当前时刻经过的毫秒数。

现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。

给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

输入描述

输入一行包含一个整数,表示时间。

输出描述

输出时分秒表示的当前时间,格式形如 HH:MM:SS,其中 HH 表示时,值为 00​​​​ 到 2323​​​​,MM 表示分,值为 00​​​​ 到 5959​​​,SS 表示秒,值为 00​​ 到 5959​。时、分、秒 不足两位时补前导 00。

输入输出样例

示例 1

输入

46800999

输出

13:00:00
示例 2

输入

1618708103123

输出

01:08:23

评测用例规模与约定

对于所有评测用例,给定的时间为不超过 10181018 的正整数。

运行限制

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

题解:

提示:1秒=1000毫秒

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

int main(int argc, char *argv[])
{
  long long n,a;
  int m,f,s;
  scanf("%lld",&n);
  a=n/1000;
  m=a%60;
  a=a/60;
  f=a%60;
  a=a/60;
  s=a%24;
  printf("%02d:%02d:%02d",s,f,m);
  return 0;
}

5.题目:括号序列(未写出)

题目描述

给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。

两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。

例如,对于括号序列 ((()(((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()()()()、()(())()(())、(())()(())()、(()())(()()) 和 ((()))((()))​。

输入描述

输入一行包含一个字符串 s,表示给定的括号序列,序列中只有左括号和右括号。

输出描述

输出一个整数表示答案,答案可能很大,请输出答案除以 10000000071000000007 (即 109+7)109+7) 的余数。

输入输出样例

示例 1

输入

((()

输出

5

评测用例规模与约定

对于 4040 的评测用例,∣s∣≤200∣s∣≤200。

对于所有评测用例,1≤∣s∣≤50001≤∣s∣≤5000。

运行限制

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

6.题目:杨辉三角形

题目描述

下面的图形是著名的杨辉三角形:

image

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯

给定一个正整数 NN,请你输出数列中第一次出现 NN 是在第几个数?

输入描述

输入一个整数 NN。

输出描述

输出一个整数代表答案。

输入输出样例

示例 1

输入

6

输出

13

评测用例规模与约定

对于 2020​​ 的评测用例,1≤N≤101≤N≤10​; 对于所有评测用例,1≤N≤10000000001≤N≤1000000000。

运行限制

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

题解:

1.(暴力,只能对一个案例)

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

int main(int argc, char *argv[])
{
  int a[100][100],i,j,k,t;
    a[0][0]=1;
    a[1][0]=1;a[1][1]=1;
    for(i=2;i<100;i++)
   {a[i][0]=1;a[i][i]=1; 
    for(j=1;j<i;j++)
    a[i][j]=a[i-1][j]+a[i-1][j-1];
   }
    
    scanf("%d",&k);
    
    for(i=0;i<100;i++)
    {for(j=0;j<=i;j++)
    {if(k==a[i][j])
    {t=1;
    printf("%d",(i+1)*i/2+j+1); 
    break;
    }
    }
    if(t==1)
    break;
    }// 请在此输入您的代码
  return 0;
}

2.

//解题思路:
//1、首先通过画图,发现杨辉三角对称,而题目要求找到数 n 最早出现的位置,
//那么我们可以确定,n最早出现的位置一定在左半边,而且最中间的是该行最大的数
//通过图,我们可以发现通过行和列的枚举是不好的,看数据1e9也就是十亿, 
//2.这是个很大的工程,因此我们试想可不可以从斜行来观察呢??
//下图我们可以观察到,第1斜行的1=C(0,0),第二斜行的2=C(2,1),第三斜行的6=C(4,2),第四斜行的20=C(6,3)…
//也就是说,如果我设共 i 斜行,那么第 i 斜行的第一个数为C(2*i,i),同时它是该斜行中最小的数字
//那么我们一定可以找到1e9的位置
//3.1e9的位置确定:
//显然C(32,16)< 1e9,而C(34,17)> 1e9,因此我们可以对前16行进行枚举
//4.枚举顺序:
//首先对于左半边杨辉三角来说,每行最大的数一定出现在该行末尾,同时它也是该数最早出现的位置
//因此我们不妨从第16斜行开始枚举,只要出现等于 n 的数直接返回位置即可
//对于查找,我们可以对每个斜行采用二分的方法查找n
//对于位置,我们可以在查找的时候确定,n所在行 r(不是斜行)和所在斜行 k ,
//然后通过等差公式 r*(r+1)/2 计算它之前数目的个数再加上 k+1
//例如:n = 20 (由于推到,第一行行号为 0 ,斜行行号也是 0)
//查找过程我们可以确定20在第7行,实际返回 r = 6 ,在第 4 斜行 ,但此时 k 是 3,因此 k+1
//结果 ans = 6*7/2 + 3 + 1 = 25
//5.时间复杂度的计算: 
//枚举16斜行 --> O(16)
//二分查找 --> O(logn)
//综合起来,算法时间复杂度为 O(16logn)
#include<stdio.h>
#include<stdlib.h>
#define ll long long 
int n;
int max(int a,int b)
{
  return a>b?a:b;
}
ll C(int a,int b)//计算二项式C(a,b) 
{
    ll res=1;
    int i,j;
    for(i=a,j=1;j<=b;i--,j++)
    {
        res=res*i/j;
        if(res>n)
        {
            return res;//如果大于n已经无意义了,因为斜行是递增的 
        }
    }
    return res;
}
int check(int k)
{
    //二分该斜行,找到大于等于该值的第一个数
    //左边界2k,右边界max(n,l),避免右边界小于左边界 
    int l=2*k,r=max(n,l);
    while(l<r)
    {
        int mid=(l+r)/2;
        if(C(mid,k)>=n) r=mid;
        else l=mid+1;
    }
    if(C(r,k)!=n)
    {
        return 0;
    }
    printf("%lld",(ll)(r+1)*r/2+k+1);
    return 1;
}
int main()
{
    scanf("%d",&n);
    int i;
    //从第16斜行枚举 
    for(i=16; ;i--)
    {
        if(check(i)==1)
        {
            break;
        }
     } 
    return 0;
}

7.题目:双向排序

题目描述

给定序列 (a1,a2,⋅⋅⋅,an)=(1,2,⋅⋅⋅,n)(a1​,a2​,⋅⋅⋅,an​)=(1,2,⋅⋅⋅,n),即 ai=iai​=i。

小蓝将对这个序列进行 mm 次操作,每次可能是将 a1,a2,⋯ ,aqia1​,a2​,⋯,aqi​​ 降序排列,或者将 aqi,aqi+1,⋯ ,anaqi​​,aqi+1​​,⋯,an​ 升序排列。

请求出操作完成后的序列。

输入描述

输入的第一行包含两个整数 n,mn,m​,分别表示序列的长度和操作次数。

接下来 mm​ 行描述对序列的操作,其中第 i 行包含两个整数 pi,qipi​,qi​​ 表示操作类型和参数。当 pi=0pi​=0​​ 时,表示将 a1,a2,⋅⋅⋅,aqia1​,a2​,⋅⋅⋅,aqi​​​​ 降序排列;当 pi=1pi​=1​ 时,表示将 aqi,aqi+1,⋯ ,anaqi​​,aqi+1​​,⋯,an​​ 升序排列。

输出描述

输出一行,包含 nn 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。

输入输出样例

示例

输入

3 3
0 3
1 2
0 2

输出

3 1 2

样例说明

原数列为 (1,2,3)(1,2,3)​​​​​。

第 11​​​​​ 步后为 (3,2,1)(3,2,1)​​​​​。

第 22​​​​ 步后为 (3,1,2)(3,1,2)​​。

第 33​​​ 步后为 (3,1,2)(3,1,2)​。与第 22 步操作后相同,因为前两个数已经是降序了。

评测用例规模与约定

对于 30%30% 的评测用例,n,m≤1000n,m≤1000;

对于 60%60% 的评测用例,n,m≤5000n,m≤5000;

对于所有评测用例,1≤n,m≤100000,0≤pi≤1,1≤qi≤n1≤n,m≤100000,0≤pi​≤1,1≤qi​≤n。

运行限制

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

题解:(暴力,十个样例只对三个,其他会超时)

#include <stdio.h>

void descendingSort(int arr[], int start, int end) {
    int i, j, temp;
    for (i = start; i < end; i++) {
        for (j = i+1; j <= end; j++) {
            if (arr[i] < arr[j]) {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

void ascendingSort(int arr[], int start, int end) {
    int i, j, temp;
    for (i = start; i < end; i++) {
        for (j = i+1; j <=end; j++) {
            if (arr[i] > arr[j]) {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);

    int arr[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }

    for (int i = 0; i < m; i++) {
        int p, q;
        scanf("%d %d", &p, &q);
        if (p == 0) {
            descendingSort(arr, 0, q - 1);
        } else {
            ascendingSort(arr, q - 1, n - 1);
        }
    }
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

8.题目:路径

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

小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径。

小蓝的图由 2021 个结点组成,依次编号 1 至 2021。

对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点 之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条 长度为 a 和 b 的最小公倍数的无向边相连。

例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。

请计算,结点 1 和结点 2021 之间的最短路径长度是多少。

提示:建议使用计算机编程解决问题。

运行限制

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

题解:

#include <stdio.h>//求1到达2021的最短路径
#include <stdlib.h>
int gcd(int a,int b)//最大公约数 辗转相除法
{
  if(a%b==0) return b;
  else return gcd(b,a%b);
}

int gbs(int a,int b)//最小公倍数=a*b/最大公约数
{
  return a*b/gcd(a,b);
}
int min(int a,int b) 
{
  return a<b?a:b;
}
int main(int argc, char *argv[]){
  int i=1,j,f[2022]={0};//f[n]表示1到n的最短路径长
/*先求1能直接到达的点(2..22)更新f数组内的数据,
把已经求出最短路径的点归到一类(i),再求这类点能直接到达的点(j)最短路径,
多个不同点能到达同一个点,可以通过循环求出f[n]的最佳结果*/
  for(i=1;i<=2021;i++){
     for(j=i+1;j<=i+21&&j<=2021;j++){
        if(f[j]==0) f[j]=f[i]+gbs(i,j);
        else f[j]=min(f[j],f[i]+gbs(i,j));
        }
      }
//比较最短路径是比较1到点j的路径长,而不是i到j的路径长!!
  printf("%d",f[2021]);
  return 0;
}

9.题目:货物摆放

题目描述

小蓝有一个超大的仓库,可以摆放很多货物。

现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。

小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n=L×W×H。

给定 nn,请问有多少种堆放货物的方案满足要求。

例如,当 n=4 时,有以下 66 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。

请问,当 n=2021041820210418 (注意有 16 位数字)时,总共有多少种方案?

提示:建议使用计算机编程解决问题。

答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

运行限制

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

题解:

#include <stdio.h>

long long n = 2021041820210418;
long long arr[1000000];

int main()
{
    int ans = 0;
    int coust = 0;
    long long i = 0;
    long long a, b, c;
    //求出所有约数
    for (i = 1; i * i <= n; i++)
    {
        if (n % i == 0)
        {
            arr[coust] = i;
            coust++;
            if (n / i != i)
            {
                arr[coust] = (n / i);
                coust++;
            }
        }
    }
    for (a =0; a < coust; a++)
        for (b = 0; b < coust; b++)
            for (c = 0; c < coust; c++)
            {
                if (arr[a]*arr[b]*arr[c] == n)
                {
                    ans++;
                }
            }
    printf("%d",ans);
    return 0;
}

10.题目:卡片

问题描述

小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一 位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有 两位同学的卡片都是一样的。

给定 n, 请问小蓝的卡片至少有多少种?

输入格式

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

输出格式

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

样例输入


6

样例输出


3

样例说明

小朋友们手中的卡片可能是: (1,1),(1,2),(1,3),(2,2),(2,3),(3,3)。

评测用例规模与约定

对于 50 的评测用例, 1≤n≤104 。

对于所有评测用例, 1≤n≤109。

运行限制

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

题解:

1.

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

int main(int argc, char *argv[])
{
  long int n,sum;
  scanf("%ld",&n);
  for(int i=1;;i++)
  {
    sum=i+(i*(i-1))/2;
    if(sum>=n)
    {
      printf("%d",i);
      break;
    }
  }
  return 0;
}

2.

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

int main()
{
  int n; cin >> n;
  int ans = 0;
  for (int i = 1, cnt = 0; i <= n; ++i)
 {
    if (cnt >= n) break;
    ans++;
    cnt += i;
  }
  cout << ans << endl;
 return 0;
}

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值