2020年B组第三场真题

Posted 揭航

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020年B组第三场真题相关的知识,希望对你有一定的参考价值。

2020年B组第三场

A_数青蛙

问题描述
“一只青蛙一张嘴,两只眼睛四条腿。两只青蛙两张嘴,四只眼睛八条腿。

三只青蛙三张嘴,六只眼睛十二条腿。……二十只青蛙二十张嘴,四十只眼睛八十条腿。”

请问上面这段文字,如果完全不省略,全部写出来,从 1 到 20 只青蛙,总共有多少个汉字。

约定:

数字 2 单独出现读成 “两”,在其他数里面读成 “二”,例如 “十二”。
10 读作 “十”,11 读作 “十一”,22 读作 “二十二”。
请只计算汉字的个数,标点符号不计算。

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

答案:353
int get_num(int n) {
	if (n >= 1 && n <= 10) { // 1 - 10
        return 1;
    } else if (n >= 11 && n <= 20 || n % 10 == 0) { // 11 - 20 整十
        return 2;
    } else {
        return 3;
    }
}

int res;

int main() {
	for (int i = 1; i <= 20; ++i) {
        res += get_num(i); // i只青蛙
    }    
    for (int i = 1; i <= 20; ++i) { // i张嘴
        res += get_num(i);
    }
    for (int i = 2; i <= 2 * 20; i += 2) { // i只眼睛
        res += get_num(i);
    }
    for (int i = 4; i <= 4 * 20; i += 4) { // i条腿
        res += get_num(i);
    }
    printf("%d", res + 200); // 除了变量 还有其他固定字符一行10个字,共20行
    return 0;
}

B_互质

问题描述
今年是 2020 年,今天是 10 月 18 日。

请问在 1 到 2020 中,有多少个数与 1018 互质。

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

答案:1008
int res;
int main() {
    for (int i = 1; i <= 2020; ++i) {
        if (__gcd(i, 1018) == 1) {
            ++res;
        }
    } 
    printf("%d\\n", res);
    return 0;
}

C_车牌

问题描述
A 市的车牌由六位组成,其中前三位可能为数字 0 至 9,或者字母 A 至 F,每位有 16 种可能。

后三位只能是数字 0 至 9。为了减少攀比,车牌中不能有连续三位是相同的字符。

例如,202020 是合法的车牌,AAA202 不是合法的车牌,因为前三个字母相同。

请问,A 市有多少个合法的车牌?

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

答案:4002750
int res;
int n = 6;
vector<int> path;

void dfs(int idx) {
    if (idx == n) {
        bool flag = true;
        // 连续三项不能重复
        for (int i = n - 1; i >= 2; --i) {
            if (path[i] == path[i - 1] && path[i - 1] == path[i - 2]) {
                flag = false;
                break;
            }
        }
        if (flag) {
            ++res;
        }
        return;
    }
    // 前3项 0 - 9
    if (idx <= 2) {
        for (int i = 0; i <= 15; ++i) {
            path.push_back(i);
            dfs(idx + 1);
            path.pop_back();
        }
    } else {
        for (int i = 0; i <= 9; ++i) {
            path.push_back(i);
            dfs(idx + 1);
            path.pop_back();
        }
    }
}
int main() {
    dfs(0);
    printf("%d\\n", res);
    return 0;
}

D_Fibonacci 集合

问题描述
小蓝定义了一个 Fibonacci 集合 F,集合的元素如下定义:

最小的 5 个 Fibonacci 数 1, 2, 3, 5, 8 属于集合 F。
如果一个元素 x 属于 F,则 3x + 2、5x + 3 和 8x + 5 都属于集合 F。
其他元素都不属于 F。
请问,这个集合中的第 2020 小元素的值是多少?

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

41269
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <queue>
#include <set>

using namespace std;

// 要小的在前面才行
priority_queue<int, vector<int>, greater<int> > qe;
set<int> se;

int main() {
    se.insert(1);
    se.insert(2);
    se.insert(3);
    se.insert(5);
    se.insert(8);

    qe.push(1);
    qe.push(2);
    qe.push(3);
    qe.push(5);
    qe.push(8);
    while (qe.size()) {
        int x = qe.top();
        qe.pop();
        // 用过了就不要再用了
        if (!se.count(3 * x + 2)) {
            qe.push(3 * x + 2);
            se.insert(3 * x + 2);
        }
        if (!se.count(5 * x + 3)) {
            qe.push(5 * x + 3);
            se.insert(5 * x + 3);
        }

        if (!se.count(8 * x + 5)) {
            qe.push(8 * x + 5);
            se.insert(8 * x + 5);
        }        
        // 数据个数要大,不能只是到2025,还有更小得
        if (se.size() >= 1e6) {
            break;
        }
    }

    int idx = 1;
    set<int>::iterator it = se.begin();
    for (it; it != se.end(); ++it) {
        if (idx >= 2025) {
            break;
        }
        printf("%d %d\\n", idx, *it);
        idx++;
    }
    return 0;
}

参考

E_上升子串

问题描述
小蓝有一个字母矩阵,他喜欢和小伙伴们在这个矩阵上玩一些游戏。

今天,他打算玩找上升子串的游戏,游戏是合作性质的。小蓝和小伙伴们首先要在矩阵中指定一个位置,

然后从这个位置开始,向上下左右相邻位置移动,移动必须满足所到达位置上的字母比当前位置大。

小蓝和小伙伴们可以移动任意多次,也可以随时停下来,这样就找到了一个上升子串。

只要子串在矩阵中的位置不同,就认为是不同的子串。

小蓝想知道,一共可以找到多少个上升子串。

小蓝的矩阵很大,已经放在了试题目录下面,叫 inc.txt。

为了更清楚的描述问题,他还找了一个很小的矩阵用来解释。例如,对于矩阵:

AB
BC
1
2
可以找到 4 个长度为 1 的上升子串、4 个长度为 2 的上升子串、2 个长度为 3 的上升子串,共 10 个。

现在,请你对于小蓝的大矩阵,找到上升子串的数量。

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

F_日期识别

题目描述
小蓝要处理非常多的数据,其中有一些数据是日期。

在小蓝处理的日期中有两种常用的形式:英文形式和数字形式。

英文形式:

每个月的英文的前三个字母作为月份标识,后面跟两位数字表示日期,

月份标识第一个字母大写,后两个字母小写,日期小于 10 时要补前导 0。

1 月到 12 月英文的前三个字母分别是 Jan、Feb、Mar、Apr、May、Jun、Jul、Aug、Sep、Oct、Nov、Dec。

数字形式:

直接用两个整数表达,中间用一个空格分隔,两个整数都不写前导 0。

其中月份用 1 至 12 分别表示 1 月到 12 月。

输入一个日期的英文形式,请输出它的数字形式。

输入格式
输入一个日期的英文形式。

输出格式
输出一行包含两个整数,分别表示日期的月和日。

输入样例1
Feb08

输出样例1
2 8

输入样例2
Oct18

输出样例2
10 18
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>

using namespace std;
string month[15] = {"0",   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

int str2int(string str) {
    int ans = 0;
    for (int i = 0; i < str.size(); ++i) {
        ans = ans * 10 + (str[i] - '0');
    }
    return ans;
}
int main() {
    string str;
    cin >> str;
    string sub_str1 = str.substr(0, 3);
    for (int i = 1; i <= 12; ++i) {
        if (month[i] == sub_str1) {
            printf("%d ", i);
            break;
        }
    }

    string sub_str2 = str.substr(3, 2);
    int num = str2int(sub_str2);
    printf("%d ", num);
    return 0;
}

G_乘法表

题目描述
九九乘法表是学习乘法时必须要掌握的。

在不同进制数下,需要不同的乘法表,例如,四进制下的乘法表如下所示:

1*1=1
2*1=2 2*2=10
3*1=3 3*2=12 3*3=21

请注意,乘法表中两个数相乘的顺序必须为样例中所示的顺序,不能随意交换两个乘数。

给定 P,请输出 P 进制下的乘法表。

输入格式
输入一个整数 P。

输出格式
输出 P 进制下的乘法表。

P 进制中大于等于 10 的数字用大写字母 A、B、C、⋯ 表示。

输入样例1
4

输出样例1

1*1=1
2*1=2 2*2=10
3*1=3 3*2=12 3*3=21

输入样例2
8

输出样例2

1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=11
4*1=4 4*2=10 4*3=14 4*4=20
5*1=5 5*2=12 5*3=17 5*4=24 5*5=31
6*1=6 6*2=14 6*3=22 6*4=30 6*5=36 6*6=44
7*1=7 7*2=16 7*3=25 7*4=34 7*5=43 7*6=52 7*7=61

数据范围
2 ≤ P ≤ 36 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>

using namespace std;

int p;
char a[100]; // 存0-9 A-Z字符
// a[] = {'0', ....., 'A', ..., 'Z'};
// P进制乘法 
// 10 * 10 = 100
// A * A =  
string get_ans(int x, int p) {
    string ans = "";
    while (x) {
        char ch = a[x % p];
        ans = ans + ch;
        x /= p;
    }
    reverse(ans.begin(), ans.end());
    return ans;
}

/*
P < 10
string ans = "";
while (x) {
    char ch = x % p + '0';
    ans = ans + ch;
    x /= p;
}
reverse(ans.begin(), ans.end());

*/
int main() {
    scanf("%d", &p);
    // 初始化
    for (int i = 0; i <= 9; ++i) {
        a[i] = i + '0';
    }
    for (int i = 10; i <= 35; ++i) {
        a[i] = i - 10 + 'A';
    }
    for (int i = 1; i <= p; ++i) {
        for (int j = 1; j <= i; ++j) {
			printf("%c*%c=", a[i], a[j]);
            cout << get_ans(i * j, p) << " ";
        }
        puts("");
    }
    // cout << get_ans(5*5, p);
    return 0;
}
11
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=11 4*4=15
5*1=5 5*2=A 5*3=14 5*4=19 5*5=23
6*1=6 6*2=11 6*3=17 6*4=22 6*5=28 6*6=33
7*1=7 7*2=13 7*3=1A 7*4=26 7*5=32 7*6=39 7*7=45
8*1=8 8*2=15 8*3=22 8*4=2A 8*5=37 8*6=44 8*7=51 8*8=59
9*1=9 9*2=17 9*3=25 9*4=33 9*5=41 9*6=4A 9*7=58 9*8=66 9*9=74
A*1=A A*2=19 A*3=28 A*4=37 A*5=46 A*6=55 A*7=64 A*8=73 A*9=82 A*A=91
B*1=10 B*2=20 B*3=30 B*4=40 B*5=50 B*6=60 B*7=70 B*8=80 B*9=90 B*A=A0 B*B=100

I_画中漂流

题目描述
在梦境中,你踏上了一只木筏,在江上漂流。

根据对当地的了解,你知道在你下游 D 米处有一个峡谷,如果你向下游前进大于等于 D 米则必死无疑。

现在你打响了急救电话,T 秒后救援队会到达并将你救上岸,水流速度是 1 米/秒,你现在有 M 点体力。

每消耗一点体力,你可以划一秒桨使船向上游前进 1 米,否则会向下游前进 1 米(水流),M 点体力需在救援队赶来前花光。

因为江面太宽了,凭借你自己的力量不可能上岸,请问,有多少种划桨的方案可以让你得救。

两个划桨方案不同是指:存在某一秒钟,一个方案划桨,另一个方案不划。

输入格式
输入一行包含三个整数 D, T, M。

输出格式
输出一个整数,表示可以让你得救的总方案数,答案可能很大,请输出方案数除以 1,000,000,007 的余数。

输入样例
1 6 3

输出样例
5

数据范围
对于 50% 的评测用例,1 ≤ T ≤ 350 
对于所有评测用例,1 ≤ T ≤ 3000 , 1 ≤ D ≤ T , 1 ≤ M ≤ 1500 1≤T≤3000

DFS 超时了

const int MOD = 1e9 + 7;

int D, T, M;
int res;

void dfs(int D, int T, int M) {
    if (T == 0) {
        res = (res + 1) % MOD;
        return;
    }

    if (M >= 1) { // 划桨 向前
        dfs(D + 1, T - 1, M - 1);
    }
    // 大于D米就不行了,就是D减少到0 等于 0 就死了
    // 不划桨
    if (D > 1) {
        dfs(D - 1, T - 1, M);
    }
}
int main() {
    scanf("%d%d%d", &D, &T, &M);
    dfs(D, T, M);
    printf("%d\\n", res);
    return 0;
}

记忆化搜索


const int MOD = 1e9 + 7;

int D, T, M;
int f[3015][1515];

int dfs(int D, int T, int M) {
    if (f[T][M] != -1) { // 已经搜索过了
        return f[T][M];
    }
    if (T == 0) {
        if (M) {
            return 0;
        }
        return f[0][0] = 1;
    }

    f[T][M] = 0;
    if (M > 0) {
        f[T][M] = (f[T][M] + dfs(D + 1, T - 1, M - 1)) % MOD;
    }
    if (D > 1) {
        f[T][M] = (f[T][M] + dfs(D - 1, T - 1, M)) % MOD;
    }
    return f[T][M];
}

int main() {
    memset(f, -1, sizeof f);
    scanf("%d%d%d", &D, &T, &M);
    printf("%d\\n", dfs(D, T, M));
    return 0;
}

以上是关于2020年B组第三场真题的主要内容,如果未能解决你的问题,请参考以下文章

2020年7月B组第一场真题

2021年B组第2场真题

2021年B组第1场真题

# 2020年第十一届蓝桥杯C/C++ B组第二场省赛真题

2020年第十一届蓝桥杯C/C++ B组第二场省赛真题

2020年第十一届蓝桥杯C/C++ B组第二场省赛真题