2024-2025 ICPC, NERC, Southern and Volga Russian Regional Contest 个人题解(A,B,C,G,J,K,L,N)

2024-2025 ICPC, NERC, Southern and Volga Russian Regional Contest 个人题解(A,B,C,G,J,K,L,N)

Dashboard - 2024-2025 ICPC, NERC, Southern and Volga Russian Regional Contest (Unrated, Online Mirror, ICPC Rules, Preferably Teams) - Codeforces

难度排序

由低到高

N、J、L、C、A、G、K、B。

火车头

#include <bits/stdc++.h>

using namespace std;

#define ft first
#define sd second

#define yes cout << "yes\n"
#define no cout << "no\n"

#define Yes cout << "Yes\n"
#define No cout << "No\n"

#define YES cout << "YES\n"
#define NO cout << "NO\n"

#define pb push_back
#define eb emplace_back

#define all(x) x.begin(), x.end()
#define all1(x) x.begin() + 1, x.end()
#define unq_all(x) x.erase(unique(all(x)), x.end())
#define unq_all1(x) x.erase(unique(all1(x)), x.end())
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL

#define RED cout << "\033[91m"     // 红色
#define GREEN cout << "\033[92m"   // 绿色
#define YELLOW cout << "\033[93m"  // 蓝色
#define BLUE cout << "\033[94m"    // 品红
#define MAGENTA cout << "\033[95m" // 青色
#define CYAN cout << "\033[96m"    // 青色
#define RESET cout << "\033[0m"    // 重置

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// typedef __int128_t i128;

typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<string, ll> psl;

typedef tuple<int, int, int> ti3;
typedef tuple<ll, ll, ll> tl3;
typedef tuple<ld, ld, ld> tld3;

typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<vi> vvi;
typedef vector<vl> vvl;

// std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());

template <typename T>
inline T read()
{
    T x = 0;
    int y = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0')
    {
        if (ch == '-')
            y = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * y;
}

template <typename T>
inline void write(T x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x >= 10)
    {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}

/*#####################################BEGIN#####################################*/
void solve()
{
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 链接:

A. Bonus Project

有一个由 \(n\) 名软件工程师组成的团队,编号从 1 到 \(n\)。他们的老板承诺,如果他们完成一个额外的项目,就会给他们发奖金。该项目总共需要 \(k\) 个工作单位。答应给第 \(i\) 位工程师的奖金是 \(a_i\) 布勒斯。老板没有给工程师分配具体任务,而是希望每个工程师都能自愿完成某个整数的工作单位。只有当项目完成时,整个团队才会获得奖金;换句话说,如果项目中自愿完成的工作单位总数大于或等于 \(k\),整个团队才会获得奖金。

每位工程师可完成的工作量不受限制。不过,所有工程师都会珍惜自己的劳动成果。第 \(i\) 位工程师估计他们的一个工作单位为 \(b_i\) 布尔。如果支付了奖金,那么第 \(i\) 位工程师完成 \(c\) 个单位的工作所获得的收益 \(s_i\) 定义为 \(s_i = a_i - c \cdot b_i\)。如果不支付奖金,工程师将不会自愿完成任何工作。

工程师们在一起工作多年,因此他们知道奖金将如何分配以及同事们对劳动的重视程度。也就是说,团队中的每个工程师都知道所有的 \(a_i\) 和所有的 \(b_i\)

工程师们都渴望获得奖金,因此他们之间商定了以下工作分配流程:

第一位工程师说:"我将完成 \(c_1\) 个工作单位",其中 \(c_1\) 是一个非负整数;
然后,第二个工程师说:"我将完成 \(c_2\) 个工作单位",其中 \(c_2\) 是一个非负整数;
......依此类推;
最后,第 \(n\) 位工程师说:"我将完成 \(c_n\) 个工作单位",其中 \(c_n\) 是一个非负整数。
每个工程师都会发出 \(c_i\) 的声音,使自己的利益 \(s_i\) 最大化。如果预期收益为零,工程师仍会同意工作以获得经验,并帮助同事获得奖金。但是,如果由于某种原因预期收益为负(工程师需要完成过多的工作或项目无法完成),该工程师将根本不工作(完成零工作量)。

鉴于每个工程师的行为都是完美的,你的任务是找出每个工程师所表达的数字 \(c_i\)

输入
第一行包含两个整数 \(n\)\(k\) ( \(1 \leq n \leq 1000\) ; \(1 \leq k \leq 10^6\) )——分别是公司的工程师人数和项目所需的工作单位数量。

第二行包含 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\) ( \(1 \leq a_i \leq 10^9\) ),其中 \(a_i\) 是项目完成后将支付给第 \(i\) 个工程师的奖金。

第三行包含 \(n\) 个整数 \(b_1, b_2, \ldots, b_n\) ( \(1 \leq b_i \leq 1000\) ),其中 \(b_i\) 是第 \(i\) 位工程师的工作单位成本。

输出
打印 \(n\) 个整数 \(c_1, c_2, \ldots, c_n\) ( \(0 \leq c_i \leq k\) )——在每个工程师都表现最优的情况下,每个工程师完成的工作量。请注意,答案是唯一的。

示例
输入

3 6
4 7 6
1 2 3

输出

1 3 2

输入

3 12
4 7 6
1 2 3

输出

0 0 0

输入

3 11
6 7 8
1 2 3

输出

6 3 2

提示
在第一个示例中,工程师们在他们之间分配了工作并获得了奖金,尽管第三位工程师的收益为零。

在第二个示例中,奖金项目需要的工作单位太多,因此工程师们不工作更有利。

解题思路

由于工作分配流程是从前往后的,因此越后面的人,选择权越小。

倒着枚举,将工作尽可能分配给后面的人即可。

搞不定数据范围设置成1000干啥,吓人吗

实现代码

void solve()
{
    int n, k;
    cin >> n >> k;
    vi a(n), b(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++)
    {
        cin >> b[i];
    }
    vi ans(n);
    int now = 0;
    for (int i = n - 1; i >= 0; i--)
    {
        int num = a[i] / b[i];
        num = min(num, k - now);
        ans[i] = num;
        now += num;
        if (now == k)
            break;
    }
    if (now < k)
    {
        for (int i = 0; i < n; i++)
        {
            cout << "0 ";
        }
        cout << "\n";
    }
    else
    {

        for (int i = 0; i < n; i++)
        {
            cout << ans[i] << " \n"[i == n - 1];
        }
    }
}

B. Make It Equal

给你一个大小为 \(n\) 的整数数组 \(a\)。数组元素的编号从 1 到 \(n\)

您可以执行以下任意次数的操作(可能为 0 次):从 1 到 \(n\) 之间选择一个索引 \(i\);将 \(a_i\) 减少 2,并将 \(a_{(i \mod n) + 1}\) 增加 1。

执行这些操作后,数组中的所有元素都应是非负等整数。

你的任务是计算最少需要执行的运算次数。

输入
第一行包含一个整数 \(t\) ( \(1 \leq t \leq 10^4\) )——测试用例数。

每个测试用例的第一行包含一个整数 \(n\) ( \(2 \leq n \leq 2 \cdot 10^5\) )。

每个测试用例的第二行包含 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\) ( \(1 \leq a_i \leq 10^9\) )。

输入的附加限制:所有测试用例中 \(n\) 的总和不超过 \(2 \cdot 10^5\)

输出
对于每个测试用例,打印一个整数——你必须执行的最小操作数。如果不可能使数组中的所有元素都相等,则打印 -1。

示例
输入

3
2
1 1
3
1 3 2
4
2 1 2 6

输出

0
-1
3

解题思路

观察发现,如果一个数组全部元素相等,那么我们可以对所有元素进行一次操作,从而让所有元素都减 \(1\)

因此,如果一个数组能够通过操作使得数组元素全部相等,且使得相等的最大元素为 \(x\) 那么,我们一定也可以构造出 \([1,x-1]\) 相等的数组。

因此,最后的相等元素 \(x\) 具有二段性,所以我们可以二分 \(x\) 是否为最大的最终相等元素。

考虑设计检查函数。

我们可以对所有数进行操作,使得 $\forall a_i \le x $,然后检查是否 $\forall a_i = a_{i+1} $。

对于一个数 \(a_i\) 要把它变为 \(x\) ,当 \(a_i \le x\) 肯定是不操作;当 \(a_i>x\) 时,如果 \(a_i-x\) 为奇数,就先对 \(a_{i-1}\) 操作一次,让其变成偶数,然后对其操作 \(\frac{a_{i}-x}{2}\) 次。

如果只操作一遍,也许任然存在 \(a_i\gt x\) ,因此我们需要循环操作 直到$\forall a_i \le x $。

看上去可能超时,考虑极限情况 \(x=0,\forall a_i=10^9\)

由于我们设计的操作函数每次会将 \(a_i\) 的值减半加到 \(a_{i+1}\) ,因此对于整体而言,我们每次都减去了 \(\frac{a_i}{2}\) ,极限情况下数组和为 \(n\times a_i\) ,因此我们总共会操作 \(log_2{a_i}\times n\) 。因此,我们检查函数的时间复杂度为 \(O(nlogV)\)

实现代码

void solve()
{
    int n;
    cin >> n;
    vi a(n);
    ll sum = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        sum += a[i];
    }
    auto check = [&](int x) -> bool
    {
        vi temp = a;
        while (1)
        {
            bool flag = true;
            for (int i = 0; i < n; i++)
            {
                if (temp[i] <= x)
                    continue;
                flag = false;
                if ((temp[i] - x) & 1)
                {
                    temp[(i - 1 + n) % n] -= 2;
                    temp[i]++;
                }
                temp[(i + 1) % n] += (temp[i] - x) / 2;
                temp[i] = x;
            }
            if (flag)
                break;
        }
        for (int i = 0; i < n; i++)
        {
            if (temp[i] != x)
                return false;
        }
        return true;
    };
    int l = 0, r = (sum + n - 1) / n;
    while (l < r)
    {
        int mid = (l + r + 1) >> 1;
        if (check(mid))
            l = mid;
        else
            r = mid - 1;
    }
    if (check(r))
        cout << sum - 1ll * r * n << "\n";
    else
        cout << "-1\n";
}

C. DIY

给你一个由 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\) 组成的列表。你需要从列表中选取 8 个元素作为四个点的坐标。这四个点应该是边平行于坐标轴的矩形的角。您的任务是选取坐标,使得到的矩形具有尽可能大的面积。矩形可以是退化矩形,即其面积可以是 0。每个整数在列表中出现的次数不限(或更少)。

输入
第一行包含一个整数 \(t\) ( \(1 \leq t \leq 25000\) )——测试用例数。

每个测试用例的第一行包含一个整数 \(n\) ( \(8 \leq n \leq 2 \cdot 10^5\) )。

每个测试用例的第二行包含 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\) ( \(-10^9 \leq a_i \leq 10^9\) )。

输入的附加限制:所有测试用例中 \(n\) 的总和不超过 \(2 \cdot 10^5\)

输出
对于每个测试用例,打印答案如下:

如果不可能构造出符合语句限制条件的矩形,则打印包含 NO(不区分大小写)字样的一行;
否则,在第一行打印 YES(不区分大小写)。在第二行中,打印 8 个整数 \(x_1, y_1, x_2, y_2, x_3, y_3, x_4, y_4\)——矩形各角的坐标。您可以按照任意顺序打印角的坐标。

示例
输入

3
16
-5 1 1 2 2 3 3 4 4 5 5 6 6 7 7 10
8
0 0 -1 2 2 1 1 3
8
0 0 0 0 0 5 0 5

输出

YES
1 2 1 7 6 2 6 7
NO
YES
0 0 0 5 0 0 0 5

解题思路

对于是否可以构建出矩阵,我们只需要检查是否存在 \(4\) 对以上相同的数即可。

对于如何找寻最大矩形,如果所以数的数量都大于 \(4\) ,那么我们一定是贪心的选择最大和最小的数作为矩形的边角,由此推得,我们一定是选择最大和次大,最小和次小的数对来构造矩形。

实现代码

void solve()
{
    int n;
    cin >> n;
    map<int, int> mp;
    for (int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        mp[x]++;
    }
    int cnt = 0;
    for (auto x : mp)
    {
        cnt += x.sd / 2;
    }
    if (cnt < 4)
    {
        NO;
        return;
    }
    int mx1 = -inf;
    int mx2 = -inf;
    int mn1 = inf;
    int mn2 = inf;
    for (auto x : mp)
    {
        if (x.sd >= 4)
        {
            mx1 = max(mx1, x.ft);
            mx2 = max(mx2, x.ft);
            mn1 = min(mn1, x.ft);
            mn2 = min(mn2, x.ft);
        }
        else if (x.sd >= 2)
        {
            if (x.ft > mx1)
            {
                mx2 = mx1;
                mx1 = x.ft;
            }
            else if (x.ft > mx2)
            {
                mx2 = x.ft;
            }
            if (x.ft < mn1)
            {
                mn2 = mn1;
                mn1 = x.ft;
            }
            else if (x.ft < mn2)
            {
                mn2 = x.ft;
            }
        }
    }
    YES;
    cout << mn1 << " " << mn2 << " " << mn1 << " " << mx1 << " " << mx2 << " " << mn2 << " " << mx2 << " " << mx1 << "\n";
}

G. Guess One Character

这是一个交互式问题。您必须在打印完每一行后立即使用 flush 操作。例如,在 C++ 中应使用函数 fflush(stdout) 或 cout.flush(),在 Java 或 Kotlin 中应使用 System.out.flush(),在 Python 中应使用 sys.stdout.flush()。

陪审团有一个由字符 0 和/或 1 组成的字符串 \(s\)。该字符串的长度为 \(n\)

您可以进行以下查询:

  1. \(t\) — " \(t\) 作为连续子串在 \(s\) 中出现了多少次?" 在这里, \(t\) 应该是一个由字符 0 和/或 1 组成的字符串;其长度至少为 1 ,最多为 \(n\)。例如,如果字符串 \(s\) 是 111011,而字符串 \(t\) 是 11,那么查询的回复就是 3。

您必须通过不超过 3 的查询猜出字符串 \(s\) 中的至少一个字符。需要注意的是,给出答案并不算一次询问。

在每个测试和每个测试用例中,字符串 \(s\) 都是事先固定的。

互动
最初,陪审团程序发送一个整数 \(t\) ( \(1 \leq t \leq 1000\) )——测试用例数。

在每个测试用例开始时,陪审团程序发送一个整数 \(n\) ( \(2 \leq n \leq 50\) )——字符串的长度。

之后,您的程序可以通过打印以下一行向陪审团程序提交查询(打印完一行后不要忘记刷新输出!):

1 \(t\) 表示询问 " \(s\) 中的连续子串 \(t\) 出现了多少次?"
对于每个查询,陪审团都会在单独一行中打印一个整数。它要么是查询的答案,如果查询是正确的,并且没有超出查询限制;或者是整数 −1 ,如果您的查询不正确(例如,未满足约束 \(1 \leq |t| \leq n\) 或字符串 \(t\) 包含 0 和 1 以外的字符),或者您在处理当前测试用例时提出了太多查询。

要提交答案,您的程序应按以下格式发送一行(打印完一行后不要忘记刷新输出!):

0 \(i\) \(c\),其中 \(1 \leq i \leq n\)\(c\) 要么为 0 要么为 1,即 \(s_i = c\)
如果您的猜测正确,陪审团程序将在单独一行中打印一个整数 1 ,表示您可以进入下一个测试用例(如果是最后一个测试用例,则终止程序),并且您提出的询问次数将被重置。如果不正确,陪审团程序将在另一行打印一个整数 −1 。

程序收到 −1 作为响应后,应立即终止。这将导致您的提交收到 "错误答案" 的裁决。如果您的程序没有终止,则您的提交结果为 "未定义"。

示例
输入

3     // 3 测试用例
3     // 字符串长度为 3

1     // 101 出现一次

1     // 猜测正确
2     // 字符串长度为 2

0     // 00 出现零次

0     // 0 出现零次

1     // 猜测正确
2     // 字符串长度为 2

1     // 1 出现一次

0     // 01 出现零次

1     // 猜测正确

输出

1 101 // 查询 101 出现多少次

0 2 0 // 猜测:s[2] 是 0

1 00  // 查询 00 出现多少次

1 0   // 查询 0 出现多少次

0 1 1 // 猜测:s[1] 是 1

1 1   // 查询 1 出现多少次

1 01  // 查询 01 出现多少次

0 2 0 // 猜测:s[2] 是 0

注意
在示例中,有 3 个测试用例:101、11 和 10。请注意,所有注释内容(// 后的内容)不会在实际问题中打印,您也不应打印这些内容。空行也是为了方便您而添加的,陪审团程序不会打印它们,您的解决方案也不应打印任何空行。

解题思路

将字符除串按长度为 \(1\) 进行划分,我们可以得到 \(0\)\(1\) 两种子字符串,按长度为 \(2\) 进行划分,我们可以得到 \(00\)\(01\)\(11\)\(10\) 四种子字符串。

观察发现,如果只存在 \(00\)\(01\) 字符串,那么 \(0\) 子字符串的数量将等于这两种字符串数量相加,那么最后一为一定是 \(1\)

实现代码

int query(string s)
{
    printf("1 %s\n", s.c_str());
    fflush(stdout);
    return read<int>();
}

void answer(int pos, char c)
{
    printf("0 %d %c\n", pos, c);
    fflush(stdout);
}
void solve()
{
    int n = read<int>();
    int n0 = query("0");
    int n00 = query("00");
    int n01 = query("01");
    if (n00 + n01 == n0)
        answer(n, '1');
    else
        answer(n, '0');
    int res = read<int>();
    assert(res == 1);
}

J. Waiting for...

Monocarp 正在公交车站等车。不幸的是,有很多人也想乘坐公共汽车。

您会得到一份两类事件的清单:

  • \(B \, b_i\) - 一辆有 \(b_i\) 个空座位的公交车到站;
  • \(P \, p_i\) - \(p_i\) 人到达车站。

这些事件按时间顺序排列。

当一辆公共汽车到达时,会发生以下情况。公交车站的所有人(除了 Monocarp)都试图进入公交车。如果有足够的空位,他们就都上车。否则,会有一些人留在公交车站(进入公交车的人数等于空余座位数)。

如果所有的人(除了 Monocarp)都进入公交车后还有至少一个空座位,那么 Monocarp 也可以决定进入这辆公交车(但他可能会选择等另一辆公交车)。对于每辆公交车,您都必须确定 Monocarp 是否有可能乘坐该公交车。

输入
第一行包含一个整数 \(n\) - 事件数量。 \((1 \leq n \leq 10^3)\)

然后是 \(n\) 行。其中第 \(i\) 行包含第 \(i\) 个事件的描述,格式如下:

  • \(B \, b_i\) \((1 \leq b_i \leq 10^6)\) - 一辆有 \(b_i\) 个空座位的公交车到站;
  • \(P \, p_i\) \((1 \leq p_i \leq 10^6)\) - \(p_i\) 人到达车站。

输入的其他限制条件:至少有一个 \(B\) 类型的事件。

输出
对于 \(B\) 类型的每个事件,如果 Monocarp 有可能占用相应的公交车,则打印 "YES",否则打印 "NO"(不区分大小写)。

示例
输入

10
P 2
P 5
B 8
P 14
B 5
B 9
B 3
P 2
B 1
B 2

输出

YES
NO
NO
YES
NO
YES

解题思路

签到题,按题意进行模拟即可。

实现代码

void solve()
{
    int n;
    cin >> n;
    ll sum = 0;
    while (n--)
    {
        char c;
        int x;
        cin >> c >> x;
        if (c == 'P')
            sum += x;
        else
        {
            sum -= x;
            if (sum < 0)
            {
                YES;
                sum = 0;
            }
            else
            {
                NO;
            }
        }
    }
}

K. Grid Walk

您有一个 \(n \times n\) 网格和两个整数 \(a\)\(b\)。行和列的编号都是从 1 到 \(n\)。我们把第 \(i\) 行和第 \(j\) 列的交点处的单元格记为 \((i,j)\)

您现在站在 \((1,1)\) 单元格,想要移动到 \((n,n)\) 单元格。

假设您现在位于 \((i,j)\) 单元格;如果存在相应的单元格,您可以一步移动到 \((i,j+1)\) 单元格或 \((i+1,j)\) 单元格。

我们将 \((i,j)\) 单元格的成本定义为

\[c(i,j) = \text{gcd}(i,a) + \text{gcd}(j,b) \]

(此处,\(\text{gcd}(x,y)\) 表示 \(x\)\(y\) 的最大公约数)。从 \((1,1)\)\((n,n)\) 的路径成本是所访问单元格(包括起始单元格和终点单元格)的成本之和。

找出成本最小的路线并打印其成本。

输入
唯一一行包含三个整数 \(n\)\(a\)\(b\) \((2 \leq n \leq 10^6; 1 \leq a,b \leq 10^6)\)

输出
打印一个整数——从 \((1,1)\)\((n,n)\) 的最便宜路线的成本。

示例
输入

4 2 4

输出

21

输入

10 210 420

输出

125

注意
第一个示例在上面的图片中描述。

解题思路

观察发现,无论我们如何操作,我们一定至少会加一遍所有的 \(\text{gcd}(i,a)\)\(\text{gcd}(j,b)\) ,我们可操作的为剩下需要加上的值 \(v\)

考虑极限情况: \(gcd(n,a)=1\)\(gcd(n,b)=1\) ,则我们一定是走边角最优,除了必加值外,我们剩下加上的值都是 \(1\)

image-20241121020611990

因此,对于任意 \(a,b,n\) 来说,我们一定是走到从第一行一直向右走,走到最远的 \(\text{maxi}=i\) 使得 \(gcd(a,i)=1\) ,然后再一直向下走,走到最远的 \(\text{maxj}=j\) 使得 \(gcd(b,j)=1\) 。然后再考虑剩下的位置这么走。

我们设 \(rn=n-\text{maxi}\)\(rm=n-\text{maxj}\) ,可以发现 \(rn\)\(rm\) 都比较小。

因为质数和任何数都互质,且质数在 \(10^6\) 内分布较为稠密,质数之间的最大间隔不会超过 \(200\),因此 \(rn \lt 200,rm \lt 200\)。可以直接进行 \(n^2\) 的 dp 。

状态转移方程:\(dp[i][j]=\min(dp[i-1][j],dp[i][j-1])+\gcd(i,a)+\gcd(j,b)\)

实现代码

void solve()
{
    int n, a, b;
    cin >> n >> a >> b;
    int maxi = 1;
    vi ga(n + 1);
    for (int i = 1; i <= n; i++)
    {
        ga[i] = __gcd(i, a);
        if (ga[i] == 1)
            maxi = i;
    }
    int maxj = 1;
    vi gb(n + 1);
    for (int i = 1; i <= n; i++)
    {
        gb[i] = __gcd(i, b);
        if (gb[i] == 1)
            maxj = i;
    }
    int ans = maxi + maxj - 2;
    for (int i = 1; i <= maxi; i++)
    {
        ans += ga[i];
    }
    for (int i = 1; i <= maxj; i++)
    {
        ans += gb[i];
    }
    int rn = n - maxi;
    int rm = n - maxj;
    vvi dp(rn + 1, vi(rm + 1, inf));
    dp[0][0] = 0;
    for (int i = 0; i <= rn; i++)
    {
        for (int j = 0; j <= rm; j++)
        {
            if (i > 0)
                dp[i][j] = min(dp[i][j], dp[i - 1][j] + ga[maxi + i] + gb[maxj + j]);
            if (j > 0)
                dp[i][j] = min(dp[i][j], dp[i][j - 1] + ga[maxi + i] + gb[maxj + j]);
        }
    }
    ans += dp[rn][rm];
    cout << ans << "\n";
}

L. Bridge Renovation

最近,Monocarp 开始担任他家附近一个公园的园长。公园很大,甚至有一条小河把它分成几个区域。河上建有几座桥。其中有三座桥特别老旧,需要修理。

三座桥的长度相同,但宽度不同。它们的宽度分别为 18、21 和 25 个单位。

在公园翻新过程中,Monocarp 必须用新木板替换作为桥面的旧木板。

木板的标准长度为 60 个单位。Monocarp 已经知道每座桥需要 \(n\) 块木板。但由于桥的宽度不同,第一座桥需要长度为 18 的 \(n\) 块木板,第二座桥需要长度为 21 的 \(n\) 块木板,最后一座桥需要长度为 25 的 \(n\) 块木板。

负责翻修的工人可以将木板切割成若干部分,但拒绝将木板连接起来,因为这样会产生薄弱点,而且看起来很难看。

Monocarp 想买尽可能少的木板,但却苦于计算不出所需木板的数量。您能帮助他吗?

输入
第一行也是唯一一行包含一个整数 \(n\) \((1 \leq n \leq 1000)\)——三座桥所需的木板数量。

输出
打印一个整数——如果木板可以切割成若干部分,则 Monocarp 覆盖所有三座桥所需的最小标准长度木板数量(60 单位)。

示例
输入

1

输出

2

输入

3

输出

4

输入

1000

输出

1167

注意
在第一个示例中,可以将一块长度为 60 的木板切割成三块长度为 25、18 和 17 的木板,再将另一块长度为 60 的木板切割成两块长度为 39 和 21 的木板。这样,Monocarp 将会得到所有所需的木板。

解题思路

观察发现第一种和第二种的木板可以任意三三组合,剩下的和第三种只能任意两两组合,因此答案为 \(\lfloor \frac{2n}{3} \rfloor +\lceil \frac{2n\%3+n}{2} \rceil\)

实现代码

void solve()
{
    int n;
    cin >> n;
    cout << (2 * n) / 3 + (2 * n % 3 + n + 1) / 2 << "\n";
}

N. Fixing the Expression

表达式是由三个字符组成的字符串,其中第一个和最后一个字符是数字(从 0 到 9),中间的字符是比较符号(<, = 或 >)。

如果比较符号与数字匹配,则表达式为真(例如,如果第一位数字严格小于最后一位数字,则比较符号应为 <)。

例如,表达式 1<3、4>2、0=0 为真,而 5>5、7<3 不是真。

给你一个字符串 \(s\),这是一个表达式。请尽可能少地更改字符,使 \(s\) 成为一个真表达式。请注意,如果 \(s\) 已经为真,则应保持原样。

输入
第一行包含一个整数 \(t\) \((1 \leq t \leq 300)\) - 测试用例数。

每个测试用例包含一行字符串 \(s\) \((|s| = 3\)\(s\) 的第一个和最后一个字符为数字,第二个字符为比较符号)。

输出
对于每个测试用例,打印一个由 3 个字符组成的字符串,即通过更改 \(s\) 中尽可能少的字符而得到的真表达式。如果有多个答案,则打印其中任何一个。

示例
输入

5
3<7
3>7
8=9
0=0
5<3

输出

3<7
8>7
8<9
0=0
0<3

解题思路

签到题,根据两边值的关系去修改符号即可。

实现代码

void solve()
{
    string s;
    cin >> s;
    int a = s[0];
    int b = s[2];
    if (a < b)
        s[1] = '<';
    else if (a == b)
        s[1] = '=';
    else
        s[1] = '>';
    cout << s << "\n";
}

封面画师id:清风残影Sid

posted @ 2024-11-21 02:43  ExtractStars  阅读(20)  评论(0编辑  收藏  举报