Codeforces Round 980 div2 個人題解(A~D)

ExtractStars發表於2024-10-21

Codeforces Round 980 div2 個人題解(A~D)

Dashboard - Codeforces Round 980 (Div. 2) - Codeforces

火車頭

#define _CRT_SECURE_NO_WARNINGS 1

#include <algorithm>
#include <array>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <chrono>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>

#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 sort_all(x) sort(all(x))
#define sort1_all(x) sort(all1(x))
#define reverse_all(x) reverse(all(x))
#define reverse1_all(x) reverse(all1(x))

#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"

// 紅色
#define DEBUG1(x)                     \
    RED;                              \
    cout << #x << " : " << x << endl; \
    RESET;

// 綠色
#define DEBUG2(x)                     \
    GREEN;                            \
    cout << #x << " : " << x << endl; \
    RESET;

// 藍色
#define DEBUG3(x)                     \
    BLUE;                             \
    cout << #x << " : " << x << endl; \
    RESET;

// 品紅
#define DEBUG4(x)                     \
    MAGENTA;                          \
    cout << #x << " : " << x << endl; \
    RESET;

// 青色
#define DEBUG5(x)                     \
    CYAN;                             \
    cout << #x << " : " << x << endl; \
    RESET;

// 黃色
#define DEBUG6(x)                     \
    YELLOW;                           \
    cout << #x << " : " << x << endl; \
    RESET;

using namespace std;

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<ld, ld> pdd;
typedef pair<ll, int> pli;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
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<pii> vpii;
typedef vector<pll> vpll;
typedef vector<pli> vpli;
typedef vector<pss> vpss;
typedef vector<ti3> vti3;
typedef vector<tl3> vtl3;
typedef vector<tld3> vtld3;

typedef vector<vi> vvi;
typedef vector<vl> vvl;

typedef queue<int> qi;
typedef queue<ll> ql;
typedef queue<pii> qpii;
typedef queue<pll> qpll;
typedef queue<psi> qpsi;
typedef queue<psl> qpsl;

typedef priority_queue<int> pqi;
typedef priority_queue<ll> pql;
typedef priority_queue<string> pqs;
typedef priority_queue<pii> pqpii;
typedef priority_queue<psi> pqpsi;
typedef priority_queue<pll> pqpll;
typedef priority_queue<psi> pqpsl;

typedef map<int, int> mii;
typedef map<int, bool> mib;
typedef map<ll, ll> mll;
typedef map<ll, bool> mlb;
typedef map<char, int> mci;
typedef map<char, ll> mcl;
typedef map<char, bool> mcb;
typedef map<string, int> msi;
typedef map<string, ll> msl;
typedef map<int, bool> mib;

typedef unordered_map<int, int> umii;
typedef unordered_map<ll, ll> uml;
typedef unordered_map<char, int> umci;
typedef unordered_map<char, ll> umcl;
typedef unordered_map<string, int> umsi;
typedef unordered_map<string, ll> umsl;

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. Profitable Interest Rate

每個測試的時間限制:1秒
每個測試的記憶體限制:256兆位元組

Alice 有 \(a\) 個硬幣。她可以開立一個名為“盈利”的銀行存款,但開立此存款所需的最低金額為 \(b\) 個硬幣。

還有一個名為“無利可圖”的存款,可以用任意數量的硬幣開立。Alice 注意到,如果她用 \(x\) 個硬幣開立“無利可圖”存款,則開立“盈利”存款所需的最低金額會減少 \(2x\) 個硬幣。但是,這些硬幣以後不能存入“盈利”存款。

如果 Alice 首先將一定數量的硬幣(可能是 0)存入“無利可圖”存款,請幫助她確定她可以存入“盈利”存款的最大硬幣數量。如果 Alice 永遠無法開立“盈利”存款,則輸出 0。

輸入

每個測試由多個測試用例組成。第一行包含一個整數 \(t\) \((1 \leq t \leq 10^4)\) — 測試用例的數量。測試用例的描述如下。

每個測試用例的一行包含兩個整數 \(a\)\(b\) \((1 \leq a, b \leq 10^9)\) — Alice 擁有的硬幣數量以及開立“盈利”存款所需的初始最低金額。

輸出

對於每個測試用例,輸出一個整數 — Alice 可以存入“盈利”存款的最大硬幣數量。如果 Alice 永遠無法開立“盈利”存款,則輸出 0。

示例

輸入

5  
10 5  
7 9  
5 100  
1 1  
1 2  

輸出

10  
5  
0  
1  
0  

注意

在第一個測試案例中,\(a \geq b\),因此 Alice 可以立即用所有 10 個硬幣開立“盈利”存款。

在第二個測試案例中,Alice 可以用 2 個硬幣開立“無盈利”存款。然後她將剩下 5 個硬幣,但開立“盈利”存款所需的最低金額將減少 4 個硬幣,使其等於 5 個硬幣。因此,Alice 將能夠用 5 個硬幣開立“盈利”存款。

在第三個測試案例中,Alice 將無法開立“盈利”存款。

解題思路

根據題目要求列出公式\(a-x=b-2x\),移項得\(x=b-a\)。再特判一下極端情況即可。

程式碼實現

void solve()
{
    ll a, b;
    cin >> a >> b;
    if (a >= b)
    {
        cout << a << endl;
        return;
    }
    else if (a * 2 <= b)
    {
        cout << 0 << endl;
        return;
    }
    int d = b - a;
    cout << a - d << endl;
}

B. Buying Lemonade

每個測試的時間限制:1秒

每個測試的記憶體限制:256兆位元組

輸入:標準輸入

輸出:標準輸出

有一臺出售檸檬水的自動售貨機。這臺機器共有 \(n\) 個槽位。你知道最初,第 \(i\) 個槽位包含 \(a_i\) 罐檸檬水。機器上還有 \(n\) 個按鈕,每個按鈕對應一個槽位,每個槽位對應一個按鈕。不幸的是,按鈕上的標籤已經磨損,所以你不知道哪個按鈕對應哪個槽位。

當你按下與第 \(i\) 個槽位對應的按鈕時,會發生以下兩種情況之一:

  1. 如果第 \(i\) 個槽位中有一罐檸檬水,它會掉出來,你會拿走它。此時,第 \(i\) 個槽位中的罐子數量減少了 \(1\)
  2. 如果第 \(i\) 個槽位中沒有剩餘的檸檬水罐,則不會掉出任何東西。

按下按鈕後,罐子會快速掉出,因此無法追蹤它從哪個槽位掉落。槽位的內容隱藏在您的視野之外,因此您無法看到每個槽位中剩餘的罐子數量。您唯一知道的是槽位中的初始罐子數量: \(a_1, a_2, \ldots, a_n\)

確定需要按下的最少按鈕次數,以保證您至少收到 \(k\) 罐檸檬水。

請注意,您可以根據是否收到罐子來調整按鈕按下時的策略。保證機器中總共至少有 \(k\) 罐檸檬水。換句話說, \(k \leq a_1 + a_2 + \ldots + a_n\)

輸入

每個測試由多個測試用例組成。第一行包含一個整數 \(t\) (\(1 \leq t \leq 10^4\)) — 測試用例的數量。測試用例的描述如下。

每個測試用例的第一行包含兩個整數 \(n\)\(k\) (\(1 \leq n \leq 2 \cdot 10^5, 1 \leq k \leq 10^9\)) — 機器中的插槽數量和所需的檸檬水罐數。

每個測試用例的第二行包含 \(n\) 個整數 \(a_1, a_2, \ldots, a_n\) (\(1 \leq a_i \leq 10^9\)) — 插槽中的罐子數量。

保證有 \(k \leq a_1 + a_2 + \ldots + a_n\) ,這意味著機器中至少有 \(k\) 罐檸檬水。

保證所有測試用例的 \(n\) 之和不超過 \(2 \cdot 10^5\)

輸出

對於每個測試用例,輸出一個整數 — 保證您收到至少 \(k\) 罐檸檬水所需的最少按鈕按下次數。

示例

輸入

5
2 1
1 1
2 2
1 2
3 4
2 1 3
10 50
1 1 3 8 8 9 12 13 27 27
2 1000000000
1000000000 500000000

輸出

1
2
5
53
1000000000

注意

在第一個測試用例中,我們可以簡單地按下第一個按鈕並收到一罐檸檬水。

在第二個測試用例中,我們可以按下每個按鈕一次,確保我們收到 \(2\) 罐檸檬水。請注意,如果我們只是按下一個按鈕兩次,我們可能不會幸運,那樣的話按鈕可能對應第一個槽位,在這種情況下我們只會收到 \(1\) 罐檸檬水。

在第三個測試用例中,最優策略之一如下:

  • 按下第一個按鈕兩次。第一次按下後,肯定會掉出一罐檸檬水。然後有兩種選擇:
    1. 如果第二次按下後沒有掉出檸檬水,我們知道這個按鈕一定對應第二個槽位,因為 \(a_2=1\)\(a_1, a_3 > 1\)。然後我們可以按下第二個按鈕兩次,第三個按鈕一次。由於 \(a_1, a_3 \geq 2\),我們肯定會在這三次按下中收到三罐檸檬水。因此,在 \(5\) 次按下後,我們將獲得 \(4\) 罐檸檬水。
    2. 如果第二次按下後掉出了一罐檸檬水,我們可以按下第二個按鈕一次,第三個按鈕一次。在每次按下中,我們肯定會收到一罐檸檬水。因此,在 \(4\) 次按下後,我們將獲得 \(4\) 罐檸檬水。

可以證明,僅用 \(4\) 次按下是無法保證收到 \(4\) 罐檸檬水的,因此答案是 \(5\)

解題思路

對於任意一個按鈕,如果我們按下之後它不再出水,那我們肯定不會再去按它。為了讓我們按按鈕的總次數儘量少,我們需要不去按下已經不出水的按鈕。

一個顯然的策略是一輪按下所有還出水的按鈕即\(a_i\gt now\)\(now\)為已經按下的次數。

為了方便維護\(a_i>now\),我們可以將\(a\)升序排序,如果\(a_i\le now\),我們可以把\(i\)往後挪直達\(a_j>now\)

觀察到\(a_i\le10^9\),不能一輪一輪模擬,需要使用除法加速。

程式碼實現

void solve()
{
    ll n, k;
    cin >> n >> k;
    vl a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    sort(all(a)); // 將罐子數量排序
    ll len = n; // 剩餘槽位數量
    ll ans = 0; // 按鈕按下的總次數
    ll now = 0; // 當前獲得的檸檬水數量
    int i = 0; // 當前槽位索引

    while (k)
    {
        // 處理當前槽位
        while (a[i] <= now) // 如果當前槽位的罐子數量小於等於已獲得的數量
        {
            i++;
            ans++; // 按下按鈕
            len--; // 剩餘槽位數量減少
        }

        // 計算當前槽位能提供的檸檬水
        if (k >= len) // 如果我們需要的數量大於或等於剩餘槽位數量
        {
            ll t = k / len; // 每個槽位至少要按下 t 次
            ll cnt = min(t, a[i] - now); // 當前槽位能提供的數量
            ans += cnt * len; // 計算總的按鈕按下次數
            now += cnt; // 更新已獲得的數量
            k -= cnt * len; // 更新還需的數量
        }
        else // 如果需要的數量小於剩餘槽位數量
        {
            ans += k; // 直接按下 k 次
            k = 0; // 更新還需的數量
        }
    }
    cout << ans << endl; // 輸出結果
}


C. Concatenation of Arrays

時間限制:每個測試 2 秒

記憶體限制:每個測試 256 兆位元組

輸入:標準輸入

輸出:標準輸出

給定 \(n\) 個陣列 \(a_1, \ldots, a_n\)。每個陣列的長度為 \(2\),因此 \(a_i = [a_{i,1}, a_{i,2}]\)。您需要將這些陣列連線成一個長度為 \(2n\) 的陣列,以使結果陣列中的逆序對數量最小化。請注意,您不需要計算實際的逆序對數量。

更正式地說,您需要選擇一個長度為 \(n\) 的排列 \(p\),以便陣列 \(b = [a_{p_1,1}, a_{p_1,2}, a_{p_2,1}, a_{p_2,2}, \ldots, a_{p_n,1}, a_{p_n,2}]\) 包含儘可能少的逆序對。

逆序對的定義是:陣列 \(c\) 中的逆序對數量是索引對 \(i\)\(j\) 的數量,使得 \(i < j\)\(c_i > c_j\)

一個長度為 \(n\) 的排列是一個由 \(n\) 個不同整陣列成的陣列,這些整數從 \(1\)\(n\) 以任意順序排列。例如, \([2,3,1,5,4]\) 是一個排列,但 \([1,2,2]\) 不是一個排列(\(2\) 在陣列中出現了兩次), \([1,3,4]\) 也不是排列(\(n=3\) 但是陣列中有 \(4\))。

輸入

每個測試由多個測試用例組成。第一行包含一個整數 \(t\) (\(1 \leq t \leq 10^4\)) — 測試用例的數量。測試用例的描述如下。

每個測試用例的第一行包含一個整數 \(n\) (\(1 \leq n \leq 10^5\)) — 陣列的數量。

接下來的每一行包含兩個整數 \(a_{i,1}\)\(a_{i,2}\) (\(1 \leq a_{i,j} \leq 10^9\)) — 第 \(i\) 個陣列的元素。

保證所有測試用例的 \(n\) 的總和不超過 \(10^5\)

輸出

對於每個測試用例,輸出 \(2n\) 個整數 — 您獲得的陣列的元素。如果有多個解決方案,則輸出其中任何一個。

示例

輸入

4
2
1 4
2 3
3
3 2
4 3
2 1
5
5 10
2 3
9 6
4 1
8 7
1
10 20

輸出

2 3 1 4
2 1 3 2 4 3
4 1 2 3 5 10 8 7 9 6
10 20

注意

在第一個測試用例中,我們以順序 \(2, 1\) 連線陣列。考慮結果陣列 \(b = [2, 3, 1, 4]\) 中的逆序對:

  • \(i=1, j=3\),因為 \(b_1=2 > 1=b_3\)
  • \(i=2, j=3\),因為 \(b_2=3 > 1=b_3\)

因此,逆序對的數量是 \(2\)。可以證明這是可能的最小逆序對數量量。

在第二個測試用例中,我們以順序 \(3, 1, 2\) 連線陣列。考慮結果陣列 \(b = [2, 1, 3, 2, 4, 3]\) 中的逆序對:

  • \(i=1, j=2\),因為 \(b_1=2 > 1=b_2\)
  • \(i=3, j=4\),因為 \(b_3=3 > 2=b_4\)
  • \(i=5, j=6\),因為 \(b_5=4 > 3=b_6\)

因此,逆序對的數量是 \(3\)。可以證明這是可能的最小逆序對數量量。

在第三個測試用例中,我們以順序 \(4, 2, 1, 5, 3\) 連線陣列。

解題思路

為了確保連線後的陣列儘可能減少逆序對數量,我們按以下規則進行排序。

  1. 最小值優先:首先根據每個陣列的最小值進行排序,可以確保在連線陣列時,較小的元素會出現在前面,從而減少後面元素大於前面元素的情況。

  2. 最大值次之:如果兩個陣列的最小值相同,則根據最大值進行排序。這是為了在最小值相同的情況下,進一步控制元素的相對順序,確保較大的元素不會在較小元素之前出現。

考慮兩個陣列 $ a = [x_1, y_1] $ 和 $ b = [x_2, y_2] $,其中 $ x_1 \leq y_1 $ 和 $ x_2 \leq y_2 $。

  • 排序依據
    • 如果 $ x_1 < x_2 $,那麼在連線時 $ x_1 $ 會在 $ x_2 $ 之前,減少逆序對。
    • 如果 $ x_1 = x_2 $,那麼需要看 $ y_1 $ 和 $ y_2 $ 的大小:
      • 如果 $ y_1 < y_2 $,那麼連線後 $ y_1 $ 會在 $ y_2 $ 之前,繼續減少逆序對。
      • 如果 $ y_1 \geq y_2 $,則可能會增加逆序對,但由於最小值相同,造成的影響相對較小。

假設我們有以下陣列:

  • $ a_1 = [1, 4] $
  • $ a_2 = [2, 3] $

如果我們不進行排序,直接連線可能得到 $ [1, 4, 2, 3] $,這裡會有逆序對(例如 $ 4 > 2 $ 和 $ 4 > 3 $),逆序對數量較多。

如果我們按照最小值排序,得到的順序是 $ a_2, a_1 $,連線後得到 $ [2, 3, 1, 4] $,這樣逆序對數量明顯減少。

程式碼實現

void solve()
{
    int n;
    cin >> n;
    vpii a(n);
    for (int i = 0; i < n; ++i)
    {
        cin >> a[i].ft >> a[i].sd;
    }
    sort(all(a), [&](const pii &x, const pii &y)
         {
        if(min(x.ft, x.sd) != min(y.ft, y.sd))
            return min(x.ft, x.sd) < min(y.ft, y.sd);
            return max(x.ft, x.sd) < max(y.ft, y.sd); });
    for (int i = 0; i < n; ++i)
    {
        cout << a[i].ft << " " << a[i].sd << " \n"[i == n - 1];
    }
}

D. Skipping

時間限制:每個測試 2 秒

記憶體限制:每個測試 256 兆位元組

輸入:標準輸入

輸出:標準輸出

現在已經是3024年,題目的想法早已用盡,奧林匹克競賽現在以經過修改的個人形式舉行。奧林匹克競賽由 \(n\) 個問題組成,編號從 \(1\)\(n\)。第 \(i\) 個問題有自己的分數 \(a_i\) 和特定引數 \(b_i\) (\(1 \leq b_i \leq n\))。

最初,測試系統會給參與者第一個問題。當參與者得到第 \(i\) 個問題時,他們有兩個選擇:

  1. 提交問題並獲得 \(a_i\) 分;
  2. 跳過這個問題,在這種情況下他們將永遠無法提交它。

然後,測試系統從索引為 \(j\) 的問題中為參與者選擇下一個問題:

  • 如果他提交了第 \(i\) 個問題,則檢視索引為 \(j < i\) 的問題;
  • 如果他跳過了第 \(i\) 個問題,則檢視索引為 \(j \leq b_i\) 的問題。

在這些問題中,它選擇索引為最大的問題,該問題以前沒有給過參與者(他以前既沒有提交過也沒有跳過過)。如果沒有這樣的問題,則參與者的比賽結束,他們的結果等於所有提交問題的分數總和。特別是,如果參與者提交了第一個問題,則他們的比賽結束。請注意,參與者最多收到每個問題一次。

Prokhor 已經為奧林匹克競賽做好了充分的準備,現在他可以提交任何問題。幫助他確定他可以獲得的最高分數。

輸入

每個測試由多個測試用例組成。第一行包含一個整數 \(t\) (\(1 \leq t \leq 10^5\)) — 測試用例的數量。測試用例的描述如下。

每個測試用例的第一行包含一個整數 \(n\) (\(1 \leq n \leq 4 \cdot 10^5\)) — 奧林匹克競賽中的問題數量。

第二行包含 \(n\) 個整數 \(a_1, a_2, \ldots, a_n\) (\(1 \leq a_i \leq 10^9\)) — 問題的分數。

第三行包含 \(n\) 個整數 \(b_1, b_2, \ldots, b_n\) (\(1 \leq b_i \leq n\)) — 問題的引數。

保證所有測試用例的 \(n\) 的總和不超過 \(4 \cdot 10^5\)

輸出

對於每個測試用例,輸出一個整數——Prokhor 可以獲得的最大分數。

示例

輸入

4
2
15 16
2 1
5
10 10 100 100 1000
3 4 1 1 1
3
100 49 50
3 2 2
4
100 200 300 1000
2 3 4 1

輸出

16
200
100
1000

注意

在第一個測試用例中,Prokhor 可以跳過第一個問題;然後他將收到索引為 \(b_1=2\) 的問題。Prokhor 可以提交它並獲得 \(a_2=16\) 分。之後,比賽將結束,因為 Prokhor 已經收到所有問題。請注意,如果 Prokhor 提交第一個問題,他將獲得 \(a_1=15\) 分,但比賽會立即結束。

在第二個測試用例中,Prokhor 可以跳過第一個問題;然後他將收到索引為 \(b_1=3\) 的問題。Prokhor 可以提交它並獲得 \(a_3=100\) 分。之後,Prokhor 將收到第二個問題,他可以跳過以接收索引為 \(b_2=4\) 的問題。Prokhor 可以提交第四個問題並獲得另一個 \(a_4=100\) 分。之後,比賽結束,因為 Prokhor 已經收到所有索引不超過 \(4\) 的問題。因此,Prokhor 將獲得總共 \(200\) 分。

在第三個測試用例中,Prokhor 可以提交第一個問題並獲得 \(100\) 分,之後比賽會立即結束。

解題思路

觀察題目發現,我們最優的策略一定是經過一系列點\(p_1,p_2,p_3\dots p_m\)到達\(p_m\)後停下,然後在\(p_m\)跳轉到所有\(i\notin P,i<p_m\)的點上獲取它們的分數,且\(\forall i\lt m,p_i\lt p_m\)。如果\(\exist p_j\gt p_m\)那我們在\(p_j\)停下一定不劣於在\(p_m\)停下。

答案\(\text{ans}=\text{min}( \text{prefix}_{p_m}-\sum^{m}_{i=1}a_{p_i}),1\le p_m\le n\)

所以我們可以建圖,然後跑最短路,算出到達每一個點的最小花費。

對於第一種操作,對\(i\rightarrow i-1\)建邊,其邊權為\(0\)

對於第二種操作,對\(i\rightarrow b_i\)建邊,其邊權為\(a_i\)

然後跑一遍dijkstra算出到達每一個點的最小代價

然後列舉所有可能的終點即可。

這題還有dp的做法,我有空補補。

程式碼實現

void solve()
{
    int n;
    cin >> n;
    vi a(n + 1);
    vl pre(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        pre[i] = pre[i - 1] + a[i];
    }
    vi b(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
    }
    vvi adj(n + 1);
    vvl w(n + 1);
    for (int i = 1; i <= n; i++)
    {
        adj[i].pb(b[i]);
        w[i].pb(a[i]);
        if (i != 1)
        {
            adj[i].pb(i - 1);
            w[i].pb(0);
        }
    }
    vl dis(n + 1, infll);
    vb vis(n + 1);
    dis[1] = 0;
    auto dijkstra = [&]()
    {
        priority_queue<pll, vpll, greater<pll>> q;
        q.push({0, 1});
        while (!q.empty())
        {
            auto t = q.top();
            q.pop();
            ll d = t.ft;
            int u = t.sd;
            if (vis[u])
                continue;
            vis[u] = true;
            for (int i = 0; i < adj[u].size(); i++)
            {
                int v = adj[u][i];
                ll cost = d + w[u][i];
                if (dis[v] > cost)
                {
                    dis[v] = cost;
                    q.push({cost, v});
                }
            }
        }
    };
    dijkstra();
    ll ans = 0;
    for (int i = 1; i <= n; i++)
    {
        ans = max(ans, pre[i] - dis[i]);
    }
    cout << ans << endl;
}

E不會寫,看不懂一點,最近這幾場掉大分,本來差12分上紫,結果狂掉270分,差點掉出藍了,場場卡B和C,導致沒時間寫後面的了,人快麻了。

相關文章