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

ExtractStars發表於2024-11-21

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

相關文章