第十三届蓝桥杯模拟赛(第二期)C++个人题解

填空题

第一题

问题描述

  小蓝的IP地址为 192.168.*.21,其中 * 是一个数字,请问这个数字最大可能是多少?

思路:

常识

答案:255

第二题

问题描述

  如果一个整数 g 能同时整除整数 A 和 B,则称 g 是 A 和 B 的公约数。例如:43 是 86 和 2021 的公约数。   请问在 1(含) 到 2021(含) 中,有多少个数与 2021 存在大于 1 的公约数。请注意 2021 和 2021 有大于 1 的公约数,因此在计算的时候要算一个。

思路:

遍历2~2021,枚举每个数与2021是否有非1的公约数。

答案:89

#include<iostream>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
const int maxn = 300 + 5;
int arr[maxn];
inline int gcd(int a, int b) {
    return b > 0 ? gcd(b, a % b) : a;
}
void solve() {
    int ans = 0;
    for (int i = 2; i <= 2021; i++) {
        int temp = gcd(i, 2021);
        if (temp != 1)ans++;
    }
    cout << ans << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第三题

问题描述

  2021 是一个非常特殊的数,它可以表示成两个非负整数的平方差,2021 = 45 * 45 - 2 * 2。   2025 也是同样特殊的数,它可以表示成 2025 = 45 * 45 - 0 * 0。   请问,在 1 到 2021 中有多少个这样的数?   请注意,有的数有多种表示方法,例如 9 = 3 * 3 - 0 * 0 = 5 * 5 - 4 * 4,在算答案时只算一次。

思路:

设 x = i * i - j * j,当 j 小于 i 时,x为正数。则暴力循环i,j即可。因为i2 - j2 = (i + j) - (i - j)。当 i 确定时,j = i - 1 为最小正数,即(i + i - 1)(i - i - 1) = 2i - 1 = 2021。 i = 1010。则为i的枚举范围。

答案:1516

#include<iostream>
#include<cstring>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
const int maxn = 2021 + 5;
int arr[maxn];
void solve() {
    memset(arr, 0, sizeof arr);
    for (int i = 1; i <= 1011; i++) {
        for (int j = 0; j < i; j++) {
            int temp = i * i - j * j;
            if (temp <= 2021)arr[temp]++;
        }
    }
    int ans = 0;
    for (int i = 1; i <= 2021; i++) {
        if (arr[i] != 0)ans++;
    }
    cout << ans << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第四题

问题描述

  小蓝要用01串来表达一段文字,这段文字包含 a, b, c, d, e, f 共 6 个字母,每个字母出现的次数依次为:a 出现 10 次,b 出现 20 次,c 出现 3 次,d 出现 4 次,e 出现 18 次,f 出现 50 次。   小蓝准备分别对每个字母使用确定的01串来表示,不同字母的01串长度可以不相同。   在表示文字时,将每个字母对应的01串直接连接起来组成最终的01串。为了能够正常还原出文字,小蓝的编码必须是前缀码,即任何一个字符对应的01串都不能是另一个字符对应的01串的前缀。   例如,以下是一个有效的编码:   a: 000   b: 111   c: 01   d: 001   e: 110   f: 100   其中 c 的长度为 2,其它字母的编码长度为 3,这种方式表示这段文字需要的总长度为:10 * 3 + 20 * 3 + 3 * 2 + 4 * 3 + 18 * 3 + 50 * 3 = 312。   上面的编码显然不是最优的,将上面的 f 的编码改为 10,仍然满足条件,但是总长度为 262,要短 50。   要想编码后的总长度尽量小,应当让出现次数多的字符对应的编码短,出现次数少的字符对应的编码长。   请问,在最优情况下,编码后的总长度最少是多少?

思路:

哈夫曼树

答案:219

#include<iostream>
#include<vector>
#include<queue>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
const int maxn = 2021 + 5;
void solve() {
    int arr[10] = { 10,20,3,4,18,50 };
    priority_queue<int, vector<int>, greater<int> > pq;
    for (int i = 0; i < 6; i++) pq.push(arr[i]);
    int ans = 0;
    while (pq.size() > 1) {
        int min1 = pq.top(); pq.pop();
        int min2 = pq.top(); pq.pop();
        ans += min1 + min2;
        pq.push(min1 + min2);
    }
    cout << ans << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第五题

问题描述

下面的矩阵中包含 ABCDEF 六种字符,请问出现最多的字符出现了几次? FFEEFEAAECFFBDBFBCDA DACDEEDCCFFAFADEFBBA FDCDDCDBFEFCEDDBFDBE EFCAAEECEECDCDECADDC DFAEACECFEADCBFECADF DFBAAADCFAFFCEADFDDA EAFAFFDEFECEDEEEDFBD BFDDFFBCFACECEDCAFAF EFAFCDBDCCBCCEADADAE BAFBACACBFCBABFDAFBE FCFDCFBCEDCEAFBCDBDD BDEFCAAAACCFFCBBAAEE CFEFCFDEEDCACDACECFF BAAAFACDBFFAEFFCCCDB FADDDBEBCBEEDDECFAFF CDEAFBCBBCBAEDFDBEBB BBABBFDECBCEFAABCBCF FBDBACCFFABEAEBEACBB DCBCCFADDCACFDEDECCC BFAFCBFECAACAFBCFBAF

思路:

map直接跑一遍就行了

答案:78

#include<iostream>
#include<string>
#include<map>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
const int maxn = 2021 + 5;
void solve() {
    map<char, int> msi;
    string str;
    while (getline(cin, str)) {
        for (auto i : str) {
            msi[i]++;
        }
    }
    int maxnum = 0;
    for (auto it : msi) {
        maxnum = max(it.second, maxnum);
    }
    cout << maxnum << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

编程题

第六题

问题描述

  小蓝要到店里买铅笔。   铅笔必须一整盒一整盒买,一整盒 12 支,价格 p 元。   小蓝至少要买 t 支铅笔,请问他最少花多少钱?

输入格式

  输入一行包含两个整数 p、t,用一个空格分隔。

输出格式

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

样例输入

5 30

样例输出

15

样例说明

  小蓝至少要买3盒才能保证买到30支铅笔,总共花费 15 元。

评测用例规模与约定

  对于所有评测用例,1 <= p <= 100,1 <= t <= 10000。

思路:

设要买的盒数为n,则12 * n ≥ t,所以n = [t / 12]

代码:

#include<iostream>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
void solve() {
    int p, t; cin >> p >> t;
    if (t % 12) {
        cout << p * (t / 12) + p << endl;
    }
    else cout << p * (t / 12) << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第七题

问题描述

  给定一个三角形的三条边的长度 a, b, c,请问这个三角形是不是一个直角三角形。

输入格式

  输入一行包含三个整数 a, b, c,表示三角形三边的长度,相邻整数之间用一个空格分隔。

输出格式

  如果是直角三角形,输出“YES”(全大写),否则输出“NO”(全大写)。

样例输入

3 4 5

样例输出

YES

样例输入

4 5 4

样例输出

NO

评测用例规模与约定

  对于所有评测用例,1 <= a, b, c <= 1000。

思路:

勾股定理

代码:

#include<iostream>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
bool isRight(int a,int b,int c) {
    if (a * a + b * b == c * c)return true;
    else return false;
}
void solve() {
    int a, b, c; 
    cin >> a >> b >> c;
    bool ans = false;
    if (a > b && a > c) ans = isRight(b, c, a);
    else if (b > a && b > c)ans = isRight(a, c, b);
    else if (c > a && c > b)ans = isRight(a, b, c);
    if (ans)cout << "YES" << endl;
    else cout << "NO" << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第八题

问题描述

  n 个小朋友正在做一个游戏,每个人要分享一个自己的小秘密。   每个小朋友都有一个 1 到 n 的编号,编号不重复。   为了让这个游戏更有趣,老师给每个小朋友发了一张卡片,上面有一个 1 到 n 的数字,每个数字正好出现一次。   每个小朋友都将自己的秘密写在纸上,然后根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。如果老师发给自己的数字正好是自己的编号,这个秘密就留在自己手里。   小朋友们拿到其他人的秘密后会记下这个秘密,老师会再指挥所有小朋友将手中的秘密继续传递,仍然根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。   这样不断重复 n 次。   现在,每个小朋友都记下了很多个秘密。   老师现在想找一些小朋友,能说出所有秘密,请问老师最少要找几个小朋友?

输入格式

  输入的第一行包含一个整数 n。   第二行包含 n 个整数 a[1], a[2], ..., a[n],相邻的整数间用空格分隔,分别表示编号 1 到 n 的小朋友收到的数字。

输出格式

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

样例输入

6 2 1 3 5 6 4

样例输出

3

样例说明

  最终小朋友 1, 2 互相知道了对方的秘密,小朋友 3 只知道自己的秘密,小朋友 4, 5, 6 互相知道了对方的秘密。   至少要找 3 个小朋友才能说出所有秘密。

评测用例规模与约定

  对于 30% 的评测用例,2 <= n <= 30。   对于 60% 的评测用例,2 <= n <= 1000。   对于所有评测用例,2 <= n <= 100000。

思路:

并查集

代码:

#include<iostream>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
int arr[maxn], tree[maxn];
int find(int x) {
    if (tree[x] == x)return x;
    else return find(tree[x]);
}
void build(int x,int y) {
    int fx = find(x);
    int fy = find(y);
    tree[fx] = fy;
}
void solve() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++) {
        tree[i] = i;
        cin >> arr[i];
    }
    for (int i = 1; i <= n; i++) {
        int x = i, y = arr[i];
        build(x, y);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (tree[i] == i)ans++;
    }
    cout << ans << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第九题

问题描述

  一个 1 到 n 的排列被称为半递增序列,是指排列中的奇数位置上的值单调递增,偶数位置上的值也单调递增。   例如:(1, 2, 4, 3, 5, 7, 6, 8, 9) 是一个半递增序列,因为它的奇数位置上的值是 1, 4, 5, 6, 9,单调递增,偶数位置上的值是 2, 3, 7, 8,也是单调递增。   请问,1 到 n 的排列中有多少个半递增序列?

输入格式

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

输出格式

  输出一行包含一个整数,表示答案,答案可能很大,请输出答案除以 1000000007 的余数。

样例输入

5

样例输出

10

样例说明

  有以下半递增序列:   (1, 2, 3, 4, 5)   (1, 2, 3, 5, 4)   (1, 2, 4, 3, 5)   (1, 3, 2, 4, 5)   (1, 3, 2, 5, 4)   (1, 4, 2, 5, 3)   (2, 1, 3, 4, 5)   (2, 1, 3, 5, 4)   (2, 1, 4, 3, 5)   (3, 1, 4, 2, 5)

评测用例规模与约定

  对于 50% 的评测用例,2 <= n <= 20。   对于所有评测用例,2 <= n <= 1000。

思路:

对n个数进行半递增排序,因为奇数和偶数上的数为递增,则当确定好奇数或者偶数上有哪些数时,递增序列有且仅有一种,并且当奇数位置的数确定时,偶数位置上的数也确定了。也就是我们可以任意的从n个数中取出m个数来确定奇数或者偶数的数,就找到一种半递增序列。这就成为了Cnm组合问题了。因为n最大为1000,远远超出int,并且还需要取模,所以这里用杨辉三角来计算组合问题。

代码:

#include<iostream>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
using pii = pair<int, int>;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 1e3 + 5;
int arr[maxn];
void solve() {
    int n; cin >> n;
    int m = n >> 1;
    for (int i = 1; i <= n; i++) {
        arr[0] = 1, arr[i] = 1;
        for (int j = i - 1; j > 0; j--) {
            arr[j] = (arr[j] + arr[j - 1]) % mod;
        }
    }
    cout << arr[m] << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

第十题

问题描述

  小蓝住在 LQ 城,今天他要去小乔家玩。   LQ 城可以看成是一个 n 行 m 列的一个方格图。   小蓝家住在第 1 行第 1 列,小乔家住在第 n 行第 m 列。   小蓝可以在方格图内走,他不愿意走到方格图外。   城市中有的地方是风景优美的公园,有的地方是熙熙攘攘的街道。小蓝很喜欢公园,不喜欢街道。他把方格图中的每一格都标注了一个属性,或者是喜欢的公园,标为1,或者是不喜欢的街道标为2。小蓝和小乔住的地方都标为了1。   小蓝每次只能从一个方格走到同一行或同一列的相邻方格。他想找到一条路径,使得不连续走两次标为 2 的街道,请问在此前提下他最少要经过几次街道?

输入格式

  输入的第一行包含两个整数 n, m,用一个空格分隔。   接下来 n 行,每行一个长度为 m 第数字串,表示城市的标注。

输出格式

  输出一行包含一个整数,表示答案。如果没有满足条件的方案,输出 -1。

样例输入

3 4 1121 1211 2211

样例输出

1

样例输入

3 4 1122 1221 2211

样例输出

-1

样例输入

5 6 112121 122221 221212 211122 111121

样例输出

5

评测用例规模与约定

  对于 50% 的评测用例,2 <= n, m <= 20。   对于所有评测用例,2 <= n, m <= 300。

思路:

用优先队列,将经过街区少的走法设为优先走法,这样找出来的第一个到达终点的就是最优解。使用普通队列的走法找出来的只是最先到达终点的走法,不一定是经过街区最少的走法

代码: 

#include<iostream>
#include<cstring>
#include<queue>
#define ios ios::sync_with_stdio(false)
#define tie cin.tie(nullptr),cout.tie(nullptr)
#define endl '\n'
using namespace std;
const int inf = 0x3f3f3f3f;
using pii = pair<int, int>;
const int mod = 1000000007;
const int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
const int maxn = 300 + 5;
char maze[maxn][maxn];
bool vis[maxn][maxn];
int  n, m, ans = inf;
class Node {
public:
    int x, y, count;
    Node(int x,int y,int count) {
        this->x = x, this->y = y, this->count = count;
    }
    friend bool operator <(const Node& a, const Node& b) {
        return a.count > b.count;
    }
};
int bfs(int x,int y,int count) {
    priority_queue<Node> pq;
    pq.push(Node(x, y, count));
    while (!pq.empty()) {
        Node tp = pq.top(); pq.pop();
        for (int i = 0; i < 4; i++) {
            int tx = tp.x + dir[i][0];
            int ty = tp.y + dir[i][1];
            if (tx > 0 && tx <= n && ty > 0 && ty <= m) {
                if (tx == n && ty == m) {
                    vis[tx][ty] = true;
                    return tp.count;
                }
                if (maze[tp.x][tp.y] == '2' && maze[tx][ty] == '2')continue;
                if (vis[tx][ty])continue;
                if (maze[tx][ty] == '2')pq.push(Node(tx, ty, tp.count + 1));
                else pq.push(Node(tx, ty, tp.count));
                vis[tx][ty] = true;
            }
        }
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> (maze[i] + 1);
    }
    memset(vis, false, sizeof vis);
    int ans = bfs(1, 1, 0);
    if (vis[n][m])cout << ans << endl;
    else cout << -1 << endl;
}
int main() {
    ios, tie;
    solve();
    return 0;
}

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值