【蓝桥】2020蓝桥杯校内模拟赛外篇

前言

本题解为第十一届软件类校内模拟赛个人题解,但非官方满分题解,因此,可能存在下列问题

  • 题意理解错误,导致答案错误。
  • 代码中存在一些问题,导致答案错误。
  • 算法复杂度的分析有误,导致不能在规定时间内得出结果。

因报名属于软件类,故本篇题解全部由 C++ 语言完成,在此参加过一次模拟后痛定思痛,思考钻研了校内模拟外篇,权当一篇解题报告。

因此蒟蒻在此提供思路为主,附有非官方题解代码,如有出错(很有可能)欢迎大佬们指正,祝大佬们们在正赛中取得好成绩√

填空题

1题目描述

一个包含有2019节点的有向图,最多包含多少条边?(不允许有重边)

4074342

众所周知,对于一个无向图,其完全图边数量的计算方式是C2n,其含义是在所有节点中选出各自独立的、不重复的两个顶点并连边。而对于有向图,将无向边视作两条有向边即可,答案为 2∗C2n


2题目描述

请问十六进制数1949对应的十进制数是多少?请特别注意给定的是十六进制,求的是十进制。

6473

令一个整型变量的值为 16进制1949,然后以十进制格式输出即可

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int num = 0x1949;
    printf("%d", num);
    return 0;
}

3题目描述

一个包含有2019个节点的二叉树,最少有多少层?
注意当一棵二叉树只有一个节点时为一层。

11

当一棵二叉树为完全二叉树(如果能的话,为满二叉树)时,其层数最少,为 ⌊log2n⌋+1

所以用换底公式来求,C语言的库函数 log() 是求自然对数的函数。若想求 logax ,可使用换底公式求 logex÷logea,即log(x)/log(a) 。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int a=2019;
    int ans=floor( log(2019) / log(2) )+1;
    printf("%d", ans);
    return 0;//11
}

4题目描述

在2019个有区别的球中选3个球放在一个盘子里,请问有多少种选法?
C(2019, 3)一算就可


编程题

5元音字母

输入格式
输入一行,包含一个单词,单词中只包含小写英文字母。
输出格式
输出一行包含一个字母,为单词中第一个出现的元音字母。若单词中不存在元音字母,输出字母n。
样例输入
hello
样例输出
e
样例输入
fly
样例输出
n
评测用例规模与约定
对于所有评测用例,单词中的字母个数不超过100。

代码:
直接遍历字符串,遇到元音字母直接返回该字母,若遍历到字符串结尾,返回字母n,结束

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
#define ri register int
const int sz = 233;
char s[sz];

char work()
{
    int len = strlen(s);
    for(int i = 0; i < len; i++)
        switch(s[i]){
            case 'a':return s[i];
            case 'e':return s[i];
            case 'i':return s[i];
            case 'o':return s[i];
            case 'u':return s[i];
        }
    return 'n';
}
int main()
{
    cin>>s;
    printf("%c", work());
    return 0;
}

6求递增序列

问题描述
在数列 a[1], a[2], …, a[n] 中,如果 a[i] < a[i+1] < a[i+2] < … < a[j],则称 a[i] 至 a[j] 为一段递增序列,长度为 j-i+1。
给定一个数列,请问数列中最长的递增序列有多长。
输入格式
输入的第一行包含一个整数 n。
第二行包含 n 个整数 a[1], a[2], …, a[n],相邻的整数间用空格分隔,表示给定的数列。
输出格式
输出一行包含一个整数,表示答案。
样例输入
7
5 2 4 1 3 7 2
样例输出
3
评测用例规模与约定
对于 50% 的评测用例,2 <= n <= 100,0 <= 数列中的数 <= 1000。
对于所有评测用例,2 <= n <= 1000,0 <= 数列中的数 <= 10000。

代码:
遍历序列,比较当前元素与下一个元素,若<则计数++,继续遍历;若>=则子序列不满足递增,使用当前已有的计数值去维护答案,将计数值重置为1

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
#define ri register int
const int sz = 10086;
int a[sz],n,ans,temp;
int main()
{
    cin>>n;
    for(int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    for(int i = 0; i < n; i++)
    {
        if(a[i+1] <= a[i])
        {
            if(temp > ans)
                ans = temp;
            temp = 1;
        }
        else
            temp++;
    }
    printf("%d", ans);
    return 0;
}

7 求无2洁净数

小明非常不喜欢数字 2,包括那些数位上包含数字 2 的数。如果一个数的数位不包含数字 2,小明将它称为洁净数。
请问在整数 1 至 n 中,洁净数有多少个?
输入格式
输入的第一行包含一个整数 n。
输出格式
输出一行包含一个整数,表示答案。
输入的第一行包含一个整数n。
第二行包含n个整数 a_1, a_2, …, a_n,相邻的整数间用空格分隔, 表示给定的数列。
输出格式
输出一行包含一个整数,表示答案。
样例输入
30
样例输出
18

  
思路:
枚举从1到n中的每个数字,并检查其任一数位是否是2,同时维护一个变量来统计个数即可。

#include <bits/stdc++.h>
using namespace std;
inline int check(int i)
{
    while(i)
    {
        if(i % 10 == 2)
            return 0;
        i /= 10;
    }
    return 1;
}
int n,ans;
int main()
{
    cin>>n;
    for(int i = 1; i <= n; i++)
        if(check(i))
            ans++;
    printf("%d", ans);
    return 0;
}

8梅花桩

问题描述
小明每天都要练功,练功中的重要的一项是梅花桩。
小明练功的梅花桩排列成 n 行 m 列, 相邻两行的距离为 1,相邻两列的距离也为 1。
小明站在第 1 行第 1 列上,他要走到第 n 行第 m 列上。小明已经练了一段时间,他现在可以一步移动不超过d的距离(直线距离)。
小明想知道,在不掉下梅花桩的情况下,自己最少要多少步可以移动到目标。
输入格式
输入的第一行包含两个整数 n, m,分别表示梅花桩的行数和列数。
第二行包含一个实数 d(最多包含一位小数),表示小明一步可以移动的距离。
输出格式
输出一个整数,表示小明最少多少步可以到达目标。
样例输入
3 4
1.5
样例输出
3
评测用例规模与约定
对于 30% 的评测用例,2 <= n, m <= 20,1 <= d <= 20。
对于 60% 的评测用例,2 <= n, m <= 100,1 <= d <= 100。
对于所有评测用例,2 <= n, m <= 1000,1 <= d <= 100

思路:
跟之前做的题目方法都差不多,连顺序都是相近的
依旧是BFS,广度优先搜索跑起来
将左上角坐标(1,1)入队,并在令 d[1][1] 处为0。不断将队头出队,并将与队头坐标 (i,j)距离 dis<d 的所有坐标入队,并将其坐标对应的 d[x][y] 标记为 d[i][j]+1 ,直到队列为空,此时d[n][m] 处即为答案。

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int sz=1010;
int dis[sz][sz];
int n,m;
double d;
queue< pair<int,int> >q;
void bfs()
{
    q.push(make_pair(1, 1));
    while(!q.empty())
    {
        pair<int,int> t = q.front();
        q.pop();
        int x = t.first, y = t.second;

        int tx = x, ty = y + (int)d;

        if((n-x)*(n-x) + (m-y)*(m-y) <= d*d)
        {
            dis[n][m] = dis[x][y] + 1;
            break;
        }
        while(tx <= n && ty >= y && ty <= m)
        {
            if((tx - x) * (tx - x) + (ty - y) * (ty - y) <= d * d && dis[tx][ty] == 0)
				{
					q.push(make_pair(tx, ty));
					dis[tx][ty] = dis[x][y] + 1;
					tx ++;
				}
				else
					ty --;
        }
    }
    cout<<dis[n][m]<<endl;
}
int main()
{
    cin>>n>>m>>d;
    bfs();
    return 0;
}

9求前向距离

问题描述
给定一个序列 a1, a2, …, an。其中 a1 是最大的数,没有其他数与 a1 相等。
对于从第二个数开始的每个数 ai,请找到位置在 ai 之前且比 ai 大的,位置上距离 ai 最近的数 aj。称为 ai 的前向距离。
对于给定的序列,请求出所有数的前向距离之和。
输入格式
输入的第一行包含一个整数 n,表示序列的长度。
第二行包含 n 个正整数,为给定的序列。
输出格式
输出一个整数,表示序列中所有数的前向距离之和。
样例输入
8
9 1 3 5 2 7 6 3
样例输出
14
评测用例规模与约定
对于 70% 的评测用例,1 <= n <= 1000。
对于所有评测用例,1 <= n <= 100000, a_i <= 1000000。
请注意答案可能很大,可能需要使用 long long 来保存。

思路:

70分方法:
对于 i>1的每个ai,向前遍历从i到1的数,直到找到第一个大于ai的数,计算其前向距离并统计答案即可。
​很显然时间复杂度为O(n2), 可以通过70%的评测用例。

100分方法:
由题意,对于一个数 ai ,若在其后有 aj>ai 则对于 aj 之后的数,aj必能替代其成为答案。

于是我们可以考虑使用一个单调递减的栈。栈中元素是一个结构体,具有序列中的某个元素 ai ,其下标 i 属性。

先将 a1 对应结构体入栈,对于随后的元素如果大于等于栈顶元素,则不断弹出直到其小于栈顶元素,此时栈顶元素为其前向元素,统计距离后将元素入栈。
如果小于栈顶元素,此时栈顶元素为其前向元素,统计距离后将元素入栈。

由于栈具有有序性质,我们可以在操作 不断弹出直到其小于栈顶元素 时使用二分法(或者一些书上叫做折半法),用 O(log2n) 时间定位到其前向元素。

则单调栈+二分的算法使得不管如何构造的数据都有O(log2n)的复杂度上界,可以通过100%评测用例。

#include<bits/stdc++.h>
typedef long long ll;
const int inf = 10000000 + 10;
const int sz = 100010;
using namespace std;
#define ri register int
inline void rd(int &x){
	char c=getchar();bool f=0;x=0;
	while(c>'9'||c<'0'){if(c=='-')f=1;c=getchar();}
	while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
	if(f) x*=-1;}
inline void we(int x){
	if(x<0) putchar('-'),x*=-1;
	if(x/10) we(x/10);
	putchar(x%10+'0');}
typedef struct{
    int index;
    int num;
} SNode;
stack<SNode> s;
int a[sz],n;
ll ans;
int main()
{
    cin>>n;
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    SNode temp;
    temp.index = 1, temp.num = a[1];
    s.push(temp);
    for(int i = 2; i <= n; i++)
    {
        while(s.top().num <= a[i])
        {
            s.pop();
        }
        ans += i - s.top().index;
        temp.index = i, temp.num = a[i];
        s.push(temp);
    }
    printf("%lld", ans);
}

10



方法千万条,AC第一条,这里所写的都仅供参考,以大赛官方为准啦,在此摆出以供大佬取其精华,去其糟粕,祝诸位大佬们节节高!

发布了75 篇原创文章 · 获赞 80 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_36693514/article/details/104869739