2026牛客寒假算法基础集训营1 补题

2026牛客寒假算法基础集训营1 思路与题解(L K C E B A G)

ninelie – Aimer,EGOIST

「Don’t be afraid daybreak has come」
 无需畏惧 黎明已然降临

官方题解:https://blog.karasu.us/wp-content/uploads/2026/02/寒假营第一场题解.pdf

L Need Zero

题意:

给定正整数 $n$。求最小的正整数 $x$,使得 $n \times x$ 的末尾为 $0$。

#include <iostream>
using namespace std;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int n;
    cin >> n;
    //答案不超过 10
    if (n % 10 == 0) cout << 1;
    else if (n % 5 == 0) cout << 2; //0,2,4,6,8 都可以通过乘以 5 变成十的倍数
    else if (n % 2 == 0) cout << 5; //反之 5 通过乘以 2 变成十的倍数
    else cout << 10;

    return 0;
}

K Constructive

题意:

构造字典序最小的,长度为 $n$ 的数组满足:

  1. 所有数字均为正整数
  2. 所有数字互不相同
  3. 所有数字的和等于所有数字的乘积
#include <iostream>
using namespace std;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        if (n == 1 || n == 3)    //注意到只有 1 和 3 有解
        {
            cout << "YES\n";
            for (int i = 1; i <= n; i++) cout << i << ' ';
            cout << '\n';
        }
        else cout << "NO\n";
    }

    return 0;
}

C Array Covering

题意:

给定一个序列,可以任意次操作,每次选择一个区间,把区间中(不包含端点)的数字都变为 $\max(a_l, a_r)$,问序列所有数字的总和最大值可以达到多少。

#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
ll a[N];

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        ll n, mx = 0;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            mx = max(mx, a[i]);    //记录数组中出现的最大值,假设下标为 idx
        }
        //则选择 (1, idx) 和 (idx, n) 将除两个端点的数字变为最大值
        ll ans = mx * (n - 2) + a[1] + a[n];
        cout << ans << '\n';
    }

    return 0;
}

注意开 long long

E Block Game

有 $n$ 个小方块排成一排,其中第 $i$ 个小方块上的数字是 $a_i$,另外还有一个万能方块上面数字是 $k$。可以任意次把万能方块从方块序列的最左侧插入,其余方块后移,同时最后一个方块变成新的万能方块。

最大化:第一个方块上的数字 + 万能方块上的数字。

#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int a[N];

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        int n, k;
        cin >> n >> k;
        a[1] = k;    //看作一个长度为 n + 1 的数组,其中把 k 排在第一位 
        for (int i = 2; i <= n + 1; i++) cin >> a[i];
        int ans = a[1] + a[n + 1];
        //两数之和即这个数和它前一个数的和
        for (int i = 2; i <= n + 1; i++) ans = max(ans, a[i] + a[i - 1]);
        cout << ans << '\n';
    }

    return 0;
}

B Card Game

题意:

一个长度为 $2 \times n$ 的排列被恰好分成了两行 $n$ 个数字($a, b$ 两数组),现在不停进行比较操作:

每次比较 $a_1$ 和 $b_1$,将大的数字删除,同一行其余数字前移。如果是 $a_1$ 被删除则得一分。

直到 $a$ 或 $b$ 被删空停止。

游戏过程如上,现在你可以在游戏开始前任意重排 $a$ 以得到最大的得分,问有多少种重排的方式可以使得得分取到可能的最大值。

思路:

以 $b$ 中的最小值 $min_b$ 为界,$a$ 中小于 $min_b$ 数的一定无法被删除,可以把这堆数全排列。

再考虑大于 $min_b$ 的数,模拟几个例子可以发现它们一定可以被删除,同样可以把这堆数全排列,答案就是两部分阶乘的乘积。

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
const int MOD = 998244353;
int a[N], b[N];

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        int n, minb = 4e5 + 5;
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= n; i++)
        {
            cin >> b[i];
            minb = min(minb, b[i]);
        }
        sort(a + 1, a + n + 1);
        int small = upper_bound(a + 1, a + n + 1, minb) - (a + 1);
        int big = n - small;
        ll ans = 1;
        for (int i = 1; i <= big; i++)
        {
            ans = ans * i % MOD;
        }
        for (int i = 1;i <= small; i++)
        {
            ans = ans * a[i] % MOD;
        }
        cout << ans << '\n';
    }

    return 0;
}

A A+B Problem

题意:

有八个独立的数位显示器,每个显示器的每个二极管被点亮的概率为 $p_i$,管与管之间互相独立,显示器之间也相互独立。求分别显示出两个四位合法数字,且数字之和等于输入的常数 $C$ 的概率。

分数取模结论

以任意分数:$\frac{a}{b}$ 为例,根据费马小定理,在模数 $m$ 为质数,且 $b$ 不是 $m$ 的倍数的情况下有:

$\frac{a}{b}\bmod m=a\times (b^{m-2})\bmod m$

思路:

从 $A + B = C$ 入手,可以将其转化为 $B = C – A$,则对于 $A$ ($0 \le A \le C$) 都有对应的 $B$,得到 $C$ 的概率为 $P(\text{显示出 } A) \times P(\text{显示出 } B)$,枚举一遍然后将每种情况的答案概率相加即可。

$A$ 和 $B$ 都为四位数,显示出这样一个四位数的概率就是用它的四位数字的概率相乘,所以要先得到一个显示器显示出 $0 – 9$ 每个数字的概率,不嫌麻烦可以每个分别手写,简便一点可以使用二进制状态压缩。

具体各部分见代码注释。

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
//const int N = 2e5 + 5;
const int MOD = 998244353;
ll p[7], digit[10], S[10];

void init() //状态压缩,存入每个 digit 需要的段码编号
{
    S[0] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6); //1110111
    S[1] = (1 << 2) | (1 << 5); //0100100
    S[2] = (1 << 0) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6);    //1011101
    S[3] = (1 << 0) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6);    //1011011
    S[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5);   //0111010
    S[5] = (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 6);    //1101011
    S[6] = (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); //1101111
    S[7] = (1 << 0) | (1 << 2) | (1 << 5);  //1010010
    S[8] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);  //1111111
    S[9] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6); //1111011
}

ll fastpower(ll base, ll pow)   //快速幂
{
    ll res = 1;
    while(pow > 0)
    {
        if (pow & 1)
        {
            res = res * base % MOD;
        }
        base = base * base % MOD;
        pow >>= 1;
    }
    return res;
}

ll probability(ll num)  //计算显示出某个四位数的概率
{
    ll ans = 1;
    for (int i = 0; i < 4; i++)
    {
        ans = ans * digit[num % 10] % MOD;
        num /= 10;
    }
    return ans;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    init();
    while (T--)
    {
        int C;
        cin >> C;
        fill(digit, digit + 10, 1);
        //读入,同时把概率从分数按要求转化为整数
        for (int i = 0; i < 7; i++)
        {
            cin >> p[i];
            p[i] = p[i] * fastpower(100, MOD - 2) % MOD;
        }
        //计算 0 到 9 每个数字出现的概率,存在 digit 数组里
        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 7; j++)
            {
                if (S[i] >> j & 1) digit[i] = digit[i] * p[j] % MOD;
                else digit[i] = digit[i] * (MOD + 1 - p[j]) % MOD;
            }
        }
        ll ans = 0;
        for (int A = 0; A <= C; A++)
        {
            int B = C - A;
            ans = (ans + (probability(A) * probability(B) % MOD)) % MOD;
        }
        cout << ans << '\n';
    }

    return 0;
}

G Digital Folding

题意:

给定区间 $[l, r], (1 \le l \le r \le 10^{15})$,定义 $f(x)$ 为把数字 $x$ 的十进制翻转后去除前导 $0$ 的值。

求区间中所有数字 $i (l \le i \le r)$ 的 $f(i)$ 最大值。

思路:

注意到从低位到高位填充尽可能多的 $9$ 可使结果最大化,考虑贪心。对于当前位 $i$,后缀均变为 $9$,第 $i$ 位数字需减一以构造出小于等于 $R$ 的最大后缀 $9$ 数值,前缀不变,从区间最大值 $R$ 的最后一位开始往前遍历,不断更新答案最大值。

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
//const int N = 2e5 + 5;

ll rev(ll x)
{
    string s = to_string(x);    //可去前导零
    reverse(s.begin(), s.end());
    return stoll(s);
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        string ls, rs;
        cin >> ls >> rs;
        ll l = stoll(ls), r = stoll(rs);
        ll ans = rev(r);    //初始化 ans 为右端点,处理末尾已有 9 或无需退位的情况
        for (int i = rs.size() - 1; i >= 0; i--)
        {
            string temp;
            if (rs[i] == '0') continue;
            for (int j = 0; j < i; j++) temp += rs[j]; //复制相同前缀
            temp += (char)(rs[i] - 1);  //当前位减一
            for (int j = i + 1; j < rs.size(); j++) temp += '9';    //后缀填充为 9
            ll temp_l = stoll(temp);
            if (temp_l >= l && temp_l <= r) ans = max(ans, rev(temp_l));
        }
        cout << ans << '\n';
    }

    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇