2020年第十一屆藍橋杯國賽個人題解


個人代碼約定

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
    // 編寫核心代碼
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    solve();
    return 0;
}

A:美麗的 2

本題總分:5 分

【問題描述】
小藍特別喜歡 2,今年是公元 2020 年,他特別高興。
他很好奇,在公元 1 年到公元 2020 年(包含)中,有多少個年份的數位中包含數字 2?

void solve() {
    int cnt = 0;
    for (int i = 2; i <= 2020; ++i) {
        int j = i;
        while (j) {
            if (j % 10 == 2) {
                cnt++;
                break;
            }
            j /= 10;
        }
    }
    cout << cnt; //563
}

B:擴散

本題總分:5 分

【題目描述】
小藍在一張無限大的特殊畫布上作畫。
這張畫布可以看成一個方格圖,每個格子可以用一個二維的整數坐標表示。
小藍在畫布上首先點了一下幾個點:(0, 0), (2020, 11), (11, 14), (2000, 2000)。
只有這幾個格子上有黑色,其它位置都是白色的。
每過一分鍾,黑色就會擴散一點。具體的,如果一個格子里面是黑色,它就會擴散到上、下、左、右四個相鄰的格子中,使得這四個格子也變成黑色(如果原來就是黑色,則還是黑色)。
請問,經過 2020 分鍾后,畫布上有多少個格子是黑色的。

跑BFS,時間在2020內都記錄,邊記錄邊累計個數,每個加個2100,從0開始,一分鍾向上擴散1,最多不超過2100

// 20312088
struct node {
    int x, y, t;
};
int nx[4] = {1, 0, -1, 0};
int ny[4] = {0, 1, 0, -1};
int e[10000][10000];
bool vis[10000][10000];
queue<node> q;
int n = 2100;
void solve() {
    node s, p;
    p.t = 0, p.x = n, p.y = n;
    q.push(p);
    p.t = 0, p.x = n + 2000, p.y = n + 2000;
    q.push(p);
    p.t = 0, p.x = n + 2020, p.y = n + 11;
    q.push(p);
    p.t = 0, p.x = n + 11, p.y = n + 14;
    q.push(p);
    vis[n][n] = vis[n + 2000][n + 2000] = vis[n + 2020][n + 11] = vis[n + 11][n + 14] = 1;

    ll ans = 4;
    while (q.size()) {
        p = q.front(), q.pop();
        for (int i = 0; i < 4; ++i) {
            s.x = p.x + nx[i];
            s.y = p.y + ny[i];
            s.t = p.t + 1;
            if (vis[s.x][s.y] == false and s.t <= 2020) {
                vis[s.x][s.y] = true;
                ans++;
                q.push(s);
            }
        }
    }
    cout << ans << "\n";
}

C階層約數

本題總分:10 分

【問題描述】
定義階乘 n! = 1 × 2 × 3 × · · · × n。
請問 100! (100 的階乘)有多少個約數。

思路:就是簡單的分解因數:\(5! = 1\times2\times3\times4\times5=2^3\times3^1\times5^1\)

using ll = long long;
void solve() {
    ll cnt[110] = {0};
    for (int i = 1; i <= 100; ++i) {
        int tmp = i;
        for (int j = 2; j <= i; ++j)
            while (tmp % j == 0) {
                tmp /= j;
                cnt[j]++;
            }
    }
    ll ans = 1;
    for (int i = 1; i <= 100; ++i) ans *= (cnt[i] + 1);
    cout << ans << "\n";
}

D:本質上升序列

本題總分:10 分

【問題描述】
小藍特別喜歡單調遞增的事物。
在一個字符串中,如果取出若干個字符,將這些字符按照在字符串中的順序排列后是單調遞增的,則成為這個字符串中的一個單調遞增子序列。

例如,在字符串 lanqiao 中,如果取出字符 n 和 q,則 nq 組成一個單調遞增子序列。類似的單調遞增子序列還有 lnq、i、ano 等等。

小藍發現,有些子序列雖然位置不同,但是字符序列是一樣的,例如取第二個字符和最后一個字符可以取到 ao,取最后兩個字符也可以取到 ao。小藍認為他們並沒有本質不同。

對於一個字符串,小藍想知道,本質不同的遞增子序列有多少個?

例如,對於字符串 lanqiao,本質不同的遞增子序列有 21 個。它們分別是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、anq、lno、ano、aio。

請問對於以下字符串(共 200 個小寫英文字母,分四行顯示):(如果你把以下文字復制到文本文件中,請務必檢查復制的內容是否與文檔中的一致。在試題目錄下有一個文件 inc.txt,內容與下面的文本相同)

tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl

本質不同的遞增子序列有多少個?
思路:

// 3616159 寫法比較暴力,輸出要等一會
using ll = long long;
map<string, int> vis;
void solve() {
    queue<pair<string, int>> q;
    string s = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
    ll ans   = 0;
    for (int i = 0; i < s.size(); ++i) {
        string tmp = "";
        tmp += s[i];
        if (!vis[tmp]) {
            vis[tmp] = 1;
            q.push({tmp, i});
            ++ans;
        }
    }
    while (q.size()) {
        string t = q.front().first;
        int pos  = q.front().second;
        q.pop();
        for (int i = pos + 1; i < s.size(); ++i)
            if (s[i] > s[pos] and !vis[t + s[i]]) {
                vis[t + s[i]] = 1;
                q.push({t + s[i], i});
                ++ans;
            }
    }
    cout << ans << "\n";
}

試題 E: 玩具蛇

本題總分:15 分

【問題描述】

小藍有一條玩具蛇,一共有 16 節,上面標着數字 1 至 16。每一節都是一個正方形的形狀。相鄰的兩節可以成直線或者成 90 度角。
小藍還有一個 4 × 4 的方格盒子,用於存放玩具蛇,盒子的方格上依次標着字母 A 到 P 共 16 個字母。
小藍可以折疊自己的玩具蛇放到盒子里面。他發現,有很多種方案可以將玩具蛇放進去。
下圖給出了兩種方案:

思路:dfs各個找一遍,實話說,這題好像比前面簡單。。

// 552
using ll = long long;
int vis[5][5];
int nexti[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
ll ans          = 0;
void dfs(int x, int y, int count) {
    if (x >= 4 || x < 0 || y >= 4 || y < 0) return;
    if (count == 16) {
        ans++;
    }
    for (int i = 0; i < 4; i++) {
        int nx = x + nexti[i][0];
        int ny = y + nexti[i][1];
        if (!vis[nx][ny]) {
            vis[nx][ny] = 1;
            dfs(nx, ny, count + 1);
            vis[nx][ny] = 0;
        }
    }
}
void solve() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            vis[i][j] = 1;
            dfs(i, j, 1);
            vis[i][j] = 0;
        }
    }
    cout << ans;
}

F: 皮亞諾曲線距離

【問題描述】
皮亞諾曲線是一條平面內的曲線。
下圖給出了皮亞諾曲線的 1 階情形,它是從左下角出發,經過一個 3 × 3 的方格中的每一個格子,最終到達右上角的一條曲線。

img

下圖給出了皮亞諾曲線的 2 階情形,它是經過一個 32 × 32 的方格中的每一個格子的一條曲線。它是將 1 階曲線的每個方格由 1 階曲線替換而成。

img

下圖給出了皮亞諾曲線的 3 階情形,它是經過一個 33 × 33 的方格中的每一個格子的一條曲線。它是將 2 階曲線的每個方格由 1 階曲線替換而成。

img

皮亞諾曲線總是從左下角開始出發,最終到達右上角。

我們將這些格子放到坐標系中,對於 k 階皮亞諾曲線,左下角的坐標是(0, 0),右上角坐標是 (3k − 1, 3k − 1),右下角坐標是 (3k − 1, 0),左上角坐標是(0, 3k − 1)。

給定 k 階皮亞諾曲線上的兩個點的坐標,請問這兩個點之間,如果沿着皮亞諾曲線走,距離是多少?

【輸入格式】
輸入的第一行包含一個正整數 k,皮亞諾曲線的階數。第二行包含兩個整數 x1, y1,表示第一個點的坐標。
第三行包含兩個整數 x2, y2,表示第二個點的坐標。

【輸出格式】
輸出一個整數,表示給定的兩個點之間的距離。

【樣例輸入】

1
0 0
2 2

【樣例輸出】

8

【樣例輸入】

2
0 2
0 3

【樣例輸出】

13

【評測用例規模與約定】
對於 30% 的評測用例,\(0 ≤ k ≤ 10\)
對於 50% 的評測用例,\(0 ≤ k ≤ 20\)
對於所有評測用例,\(0 ≤ k ≤ 100, 0 ≤ x1, y1, x2, y2 < 3k, x1, y1, x2, y2 ≤ 10^{18}\)
數據保證答案不超過 \(10^{18}\)

沒怎么看懂題,跳過了

G: 游園安排

【問題描述】

L 星球游樂園非常有趣,吸引着各個星球的游客前來游玩。小藍是 L 星球游樂園的管理員。
為了更好的管理游樂園,游樂園要求所有的游客提前預約,小藍能看到系統上所有預約游客的名字。每個游客的名字由一個大寫英文字母開始,后面跟0 個或多個小寫英文字母。游客可能重名。
小藍特別喜歡遞增的事物。今天,他決定在所有預約的游客中,選擇一部分游客在上午游玩,其他的游客都在下午游玩,在上午游玩的游客要求按照預約的順序排列后,名字是單調遞增的,即排在前面的名字嚴格小於排在后面的名字。
一個名字 A 小於另一個名字 B 是指:存在一個整數 i,使得 A 的前 i 個字母與 B 的前 i 個字母相同,且 A 的第 i+1 個字母小於 B 的第 i+1 個字母。(如果 A 不存在第 i + 1 個字母且 B 存在第 i + 1 個字母,也視為 A 的第 i + 1 個字母小於 B 的第 i + 1 個字母)
作為小藍的助手,你要按照小藍的想法安排游客,同時你又希望上午有盡量多的游客游玩,請告訴小藍讓哪些游客上午游玩。如果方案有多種,請輸出上午游玩的第一個游客名字最小的方案。如果此時還有多種方案,請輸出第一個游客名字最小的前提下第二個游客名字最小的方案。如果仍然有多種,依此類推選擇第三個、第四個……游客名字最小的方案。

【輸入格式】

輸入包含一個字符串,按預約的順序給出所有游客的名字,相鄰的游客名字之間沒有字符分隔。

【輸出格式】

按預約順序輸出上午游玩的游客名單,中間不加任何分隔字符。

【樣例輸入】

WoAiLanQiaoBei

【樣例輸出】

AiLanQiao

【評測用例規模與約定】
對於 20% 的評測數據,輸入的總長度不超過 20 個字母。
對於 50% 的評測數據,輸入的總長度不超過 300 個字母。
對於 70% 的評測數據,輸入的總長度不超過 10000 個字母。
對於所有評測數據,每個名字的長度不超過 10 個字母,輸入的總長度不超
過 1000000 個字母。

思路:排個順序,比較字母個數,小字母多的放前面,一樣多的,小字母靠前放前面

寫法有點暴力,不能保證AC 100%數據

string x[1000001];
bool cmp(string a, string b) {
    int visa[30] = {0}, visb[30] = {0};
    visa[a[0] - 'A']++;
    visb[b[0] - 'A']++;
    for (int i = 1; i < a.length(); i++)
        visa[a[i] - 'a']++;
    for (int i = 1; i < b.length(); i++)
        visb[b[i] - 'a']++;
    int mn = min(a.length(), b.length());
    for (int i = 0; i < mn; i++) {
        if (visa[i] > visb[i]) return 1;
        else if (visa[i] < visb[i])
            return 0;
    }
    if (a.length() > b.length()) return 0;
    else if (a.length() < b.length())
        return 1;
    else {
        for (int i = 0; i < mn; i++)
            if (a[i] > b[i]) return 0;
            else if (a[i] < b[i])
                return 1;
        return 1;
    }
}
void solve() {
    string ch;
    cin >> ch;
    int i = 0;
    int n = -1;
    while (i <= ch.size()) {
        if (ch[i] >= 'A' and ch[i] <= 'Z') {
            n++;
            x[n] += ch[i];
        } else if (ch[i] != '\0')
            x[n] += ch[i];
        ++i;
    }
    n++;
    sort(x, x + n, cmp);
    for (int i = 0; i <= n / 2; ++i) cout << x[i];
    cout << "\n";
}

H: 答疑

【問題描述】
有 n 位同學同時找老師答疑。每位同學都預先估計了自己答疑的時間。老師可以安排答疑的順序,同學們要依次進入老師辦公室答疑。

一位同學答疑的過程如下:

首先進入辦公室,編號為 i 的同學需要 si 毫秒的時間。
然后同學問問題老師解答,編號為 i 的同學需要 ai 毫秒的時間。
答疑完成后,同學很高興,會在課程群里面發一條消息,需要的時間可 以忽略。
最后同學收拾東西離開辦公室,需要 ei 毫秒的時間。一般需要 10 秒、20 秒或 30 秒,即 ei 取值為 10000,20000 或 30000。
一位同學離開辦公室后,緊接着下一位同學就可以進入辦公室了。
答疑從 0 時刻開始。老師想合理的安排答疑的順序,使得同學們在課程群里面發消息的時刻之和最小。

【輸入格式】
輸入第一行包含一個整數 n,表示同學的數量。
接下來 n 行,描述每位同學的時間。其中第 i 行包含三個整數 si, ai, ei,意義如上所述。

【輸出格式】
輸出一個整數,表示同學們在課程群里面發消息的時刻之和最小是多少。

【樣例輸入】

3
10000 10000 10000
20000 50000 20000
30000 20000 30000

【樣例輸出】
280000

【樣例說明】
按照 1, 3, 2 的順序答疑,發消息的時間分別是 20000, 80000, 180000。

【評測用例規模與約定】
對於 30% 的評測用例,1 ≤ n ≤ 20。
對於 60% 的評測用例,1 ≤ n ≤ 200。
對於所有評測用例,1 ≤ n ≤ 1000,1 ≤ si ≤ 60000,1 ≤ ai ≤ 1000000,ei ∈ {10000, 20000, 30000},即 ei 一定是 10000、20000、30000 之一。

思路:s+e+a小的放前面,一樣的就把s+a小的放前面

寫法有點暴力,不能保證AC 100%數據

using ll = long long;
struct student {
    ll s, a, e;
} stu[1001];
bool cmp(const student n1, const student n2) {
    ll sum1 = n1.s + n1.a, sum2 = n2.s + n2.a;
    if (sum1 + n1.e > sum2 + n2.e) return 0;
    else if (sum1 + n1.e < sum2 + n2.e)
        return 1;
    else {
        if (sum1 > sum2) return 0;
        else if (sum1 < sum2)
            return 1;
        else
            return 1;
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> stu[i].s >> stu[i].a >> stu[i].e;
    }
    sort(stu, stu + n, cmp);
    ll ans = 0, k = 0;
    for (int i = 0; i < n; i++) {
        k = k + stu[i].s + stu[i].a;
        ans += k;
        k += stu[i].e;
    }
    cout << ans << endl;
}

I: 出租車

待補

J: 質數行者

待補


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM