【藍橋】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第一條,這裏所寫的都僅供參考,以大賽官方爲準啦,在此擺出以供大佬取其精華,去其糟粕,祝諸位大佬們節節高!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章