【2024浙江省蓝桥杯C++B组省赛】题解A-D(含题面)

这里是paoxiaomo,一个现役ACMer,之后将会持续更新算法笔记系列以及笔试题题解系列

本文章面向想打ICPC/蓝桥杯/天梯赛等程序设计竞赛,以及各个大厂笔试的选手

感谢大家的订阅➕ 和 喜欢

试题A: 进制

本题总分:5分

【问题描述】 8100178706957568 这个数在用 x 进制表示时 (x ∈ [11,36]),仅包含数字而 不包含字母,请问x是多少。比如2588用16进制表示为a1c,包含字母a和 c。

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

【题目解析】

暴力枚举每个数字,一一检验,可得答案为32.

试题B: 逆序对期望

本题总分:5分 【问题描述】 有一个数组,包含1到n这n个整数,初始为一个从小到大的有序排列: {1, 2, 3, 4,··· ,n} 。一次随机交换操作指:均匀随机选取两个位置 i, j ∈ [1,n] 且 i \neqj ,然后交换数组中这两个位置上的数。那么对于n=51,对初始数组进行 两次随机交换操作之后,数组中的逆序对的数量的期望是多少个。 【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个实数,在提交答案时只填写这个实数,四舍五入保留两位小数,填写多余的 内容将无法得分.

【题目解析】

暴力打表题,枚举每次交换的两个数字,然后检验即可,答案为65.33.

试题C: 传送阵

时间限制: 1.0s 内存限制: 256.0MB 本题总分:10分

【问题描述】 小蓝在环球旅行时来到了一座古代遗迹,里面并排放置了n个传送阵,进 入第i个传送阵会被传送到第ai 个传送阵前,并且可以随时选择退出或者继续 进入当前传送阵。 小蓝为了探寻传送阵中的宝物,需要选择一个传送阵进入,然后连续进入 之后的传送阵。小蓝希望尽可能多地进入传送门以便搜索宝物,同时他可以使 用一次魔法,从某个传送阵 j走到相邻的(第 j−1或第 j+1个)传送阵,请 问小蓝最多能到达多少个不同的传送阵?一个传送阵可多次进入,但在计算答 案时只算一个。

【输入格式】 输入的第一行包含一个正整数n。 第二行包含n个正整数a1,a2,··· ,an ,相邻整数之间使用一个空格分隔。

【输出格式】 输出一行包含一个整数表示答案。

【样例输入】

5

2 1 5 4 3

【样例输出】 4

【样例说明】 小蓝的路径可以是:1→2→3→5。其中2→3使用魔法。 

【评测用例规模与约定】 对于20%的评测用例,1≤n≤1000; 对于所有评测用例,1≤n≤106,且a是1至n的一个排列。

【题目解析】

由a是1至n的一个排列这个条件得知,每个位置只有唯一的一个传送门能到达,由此推断,这个图是由一堆简单环组成,而每个环上各个点又是可以到达的,所以直接将环上点进行染色后枚举每两个相邻位置,如果两者颜色不同则可以相加并取最大值。

【参考代码】

void solve()
{
    int n, tot = 0;
    cin >> n;
    vector a(n + 1), co(n + 1), siz(n + 1); // 输入数组,每个位置连通块的颜色,每种颜色的联通块大小
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    auto dfs = [&](int pos, auto dfs) -> void
    {
        co[pos] = tot;
        siz[tot]++;
        if (!co[a[pos]])
        {
            dfs(a[pos], dfs);
        }
    };
    for (int i = 1; i <= n; i++)
    {
        if (!co[i])
            ++tot, dfs(i, dfs);
    }
    if (tot == 1)
    { // 特判所有的都在一个环上的情况
        cout << n << endl;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        if (co[i] != co[i - 1])
        {
            ans = max(ans, siz[co[i]] + siz[co[i - 1]]); // 尽量取最大的两个相邻连通块
        }
    }
    cout << ans << endl;
}

试题D: 前缀总分

时间限制: 1.0s

内存限制: 256.0MB 本题总分:10分

【问题描述】 给定n 个由小写英文字母组成的字符串 s1,s2,··· ,sn ,定义前缀总分为 V = ∑

i

【输入格式】 输入的第一行包含一个正整数n。 接下来n行,每行包含一个字符串s_i。

【输出格式】 输出一行包含一个整数表示答案。

【样例输入】

3

aab

bbb

abb

【样例输出】

5

【样例说明】 将第二个字符串改为abb,得分为P(aab,abb)+P(aab,abb)+P(abb,abb) = 1 +1+3=5

【评测用例规模与约定】 对于20%的评测用例,1≤n≤20; 对于所有评测用例,1≤n≤200,1≤|si|≤200 ,其中 |si| 表示 si的长度。

【题目解析】

进行大量的字符串匹配问题,可以使用字典树来进行匹配,我们可以先建立字典树,然后枚举每个字符串上的每个字母并替换,对于每个被替换后的字符串一一跑一遍字典树即可,记得在统计前先将当前字符串的贡献删去。

【参考代码】

int tr[4005][26], tot, num[4005];
string s[205];
void solve()
{
    int n;
    cin >> n;
    int sum = 0, ans = 0; // 先统计所有的字符串如果不改变那么和是多少,用sum记录
    for (int i = 1; i <= n; i++)
    {
        cin >> s[i];
        int now = 0;
        for (int j = 0; j < s[i].size(); j++)
        { // 经典字典树操作
            if (!tr[now][s[i][j] - 'a'])
            {
                tr[now][s[i][j] - 'a'] = ++tot;
            }
            now = tr[now][s[i][j] - 'a'];
            sum += num[now];
            num[now]++;
        }
    }
    ans = sum;
    for (int i = 1; i <= n; i++)
    {
        int now = 0;
        for (int j = 0; j < s[i].size(); j++)
        {
            if (!tr[now][s[i][j] - 'a'])
            {
                tr[now][s[i][j] - 'a'] = ++tot;
            }
            now = tr[now][s[i][j] - 'a'];
            num[now]--;
            sum -= num[now]; // 减去该串的贡献
        }
        for (int j = 0; j < s[i].size(); j++)
        {
            char fore = s[i][j]; // 记录原来的字符,方便改回去
            for (int k = 0; k < 26; k++)
            {
                s[i][j] = 'a' + k;
                now = 0;
                int nu = 0;
                for (int j = 0; j < s[i].size(); j++)
                {
                    if (!tr[now][s[i][j] - 'a'])
                    {
                        break;
                    }
                    now = tr[now][s[i][j] - 'a'];
                    nu += num[now]; // 加上变换后该串的贡献
                }
                ans = max(ans, nu + sum);
            }
            s[i][j] = fore;
        }
        now = 0;
        for (int j = 0; j < s[i].size(); j++)
        {
            if (!tr[now][s[i][j] - 'a'])
            {
                tr[now][s[i][j] - 'a'] = ++tot;
            }
            now = tr[now][s[i][j] - 'a'];
            sum += num[now];
            num[now]++; // 回退操作
        }
    }
    cout << ans << endl;
}

剩下的题目下次再更新。关注博主可以更快看到文章哦~

你可能感兴趣的:(算法,数据结构,蓝桥杯)