Codeforces Round 950 (Div. 3)個人題解(A~F1)

ExtractStars發表於2024-06-04

Codeforces Round 950 (Div. 3)個人題解(A~F1)

題解火車頭

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <list>
#include <bitset>
#include <cmath>
#include <numeric>

#define endl '\n'

#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 unq_all(x) x.erase(unique(all(x)), x.end())
#define sort_all(x) sort(all(x))
#define reverse_all(x) reverse(all(x))

#define INF 0x7fffffff
#define INFLL 0x7fffffffffffffffLL

#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 pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ld, ld> pdd;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
typedef pair<string, ll> psl;

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<pss> vpss;

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> pqpl;
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;

template <typename T>
inline void read(T &x)
{
    T f = 1;
    x = 0;
    char ch = getchar();
    while (0 == isdigit(ch))
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (0 != isdigit(ch))
        x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
    x *= f;
}

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

A. Problem Generator

題意

A. 問題生成器
每個測試的時間限制:1秒
每個測試的記憶體限制:256兆位元組
輸入:標準輸入
輸出:標準輸出

弗拉德計劃在下個月舉行 m 輪比賽。每輪比賽應包含一個難度為 "A"、"B"、"C"、"D"、"E"、"F" 和 "G" 的問題。

弗拉德已經有了一個 n 個問題的題庫,其中第 i 個問題的難度等級為 ai。題庫中的問題可能不夠,所以他可能需要再想出一些問題。

弗拉德想要儘可能少地提出問題,所以他要求你找出他需要提出的問題的最小數量,以便舉行 m 輪比賽。

例如,如果 m=1,n=10,a='BGECDCBDED',那麼他需要想出兩道題:一道難度為 "A",一道難度為 "F"。

輸入

第一行包含一個整數 t(1≤t≤1000)——測試用例的數量。

每個測試用例的第一行包含兩個整數 n 和 m(1≤n≤50,1≤m≤5)——題庫中的問題數量和即將舉行的輪數。

每個測試用例的第二行包含一個長度為 n 的字串 a,字串中的字元從 'A' 到 'G',表示題庫中問題的難度。

輸出

對於每個測試用例,輸出一個整數——為了舉行 m 輪比賽,需要提出的最小問題數量。

示例

輸入

3
10 1
BGECDCBDED
10 2
BGECDCBDED
9 1
BBCDEFFGG

輸出

2
5
1

解題思路

對於每個字母,如果不足\(m\),就加入最終答案

題解

void solve()
{
    int n, m;
    cin >> n >> m;
    string s;
    cin >> s;
    ll ans = 0;
    vi mp(7);
    for (auto c : s)
    {
        mp[c - 'A']++;
    }
    for (auto i : mp)
    {
        ans += max(0, m - i);
    }
    cout << ans << endl;
}

B. Choosing Cubes

題意

B. 選擇立方體
每個測試的時間限制:1秒
每個測試的記憶體限制:256兆位元組
輸入:標準輸入
輸出:標準輸出

德米特里有 n 個立方體,從左到右編號為 1 到 n。索引為 f 的立方體是他的最愛。

德米特里把所有的立方體都扔到了桌子上,第 i 個立方體顯示了數值 ai(1≤ai≤100)。之後,他按照數值從大到小的非遞增順序排列這些立方體。如果兩個立方體顯示的數值相同,它們可以按照任何順序排列。

排序後,德米特里取出了前 k 個立方體。然後,他開始關注自己是否取出了最喜歡的立方體(注意,排序後立方體的位置可能會發生變化)。

例如,如果 n=5,f=2,a=[4,3,3,2,3](最喜歡的立方體用綠色標出),k=2,可能會發生以下情況:

  • 在對 a=[4,3,3,3,2] 進行排序後,由於最喜歡的立方體排在了第二位,因此它將被移除。
  • 在對 a=[4,3,3,3,2] 進行排序後,由於最喜愛的立方體排在了第三位,因此它不會被移除。

輸入

第一行包含一個整數 t(1≤t≤1000)——測試用例的數量。然後是測試用例的說明。

每個測試用例描述的第一行分別包含三個整數 n、f 和 k(1≤f,k≤n≤100)——立方體的數量、德米特里最喜歡的立方體的索引以及移除的立方體的數量。

每個測試用例描述的第二行包含 n 個整數 ai(1≤ai≤100)——立方體上顯示的值。

輸出

對於每個測試用例,輸出一行——如果立方體在所有情況下都會被移除,則輸出 "YES";如果在任何情況下都不會被移除,則輸出 "NO";如果可能會被移除或留下,則輸出 "MAYBE"。

您可以輸出任何情況下的答案。例如,"YES"、"nO"、"mAyBe" 等字串都可以作為答案。

示例

輸入

12
5 2 2
4 3 3 2 3
5 5 3
4 2 1 3 5
5 5 2
5 2 4 1 3
5 5 5
1 2 5 4 3
5 5 4
3 1 2 4 5
5 5 5
4 3 2 1 5
6 5 3
1 2 3 1 2 3
10 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1
42
5 2 3
2 2 1 1 2
2 1 1
2 1
5 3 1
3 3 2 3 2

輸出

MAYBE
YES
NO
YES
YES
YES
MAYBE
MAYBE
YES
YES
YES
NO

解題思路

我們只需要檢查排完序之後比較在 $ k $ 位置的立方體\(a_k\)與最喜歡的立方體\(a_f\)的大小即可,如果\(a_k>a_f\),說明\(a_f\)的位置在\(k\)之前,一定會被刪;如果\(a_k<a_f\),說明\(a_f\)的位置在\(k\)之後,一定不會被刪;如果\(a_k=a_f\),檢查\(a_{k+1}\),如果\(a_{k+1}=a_f\),則有可能被刪,否則一定被刪。

題解

void solve()
{
    int n, f, k;
    cin >> n >> f >> k;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int fa = a[f];
    sort(a.begin() + 1, a.end(), greater<int>());
    if (k == n)
        YES;
    else if (fa > a[k])
        YES;
    else if (fa < a[k])
        NO;
    else
    {
        if (a[k + 1] == fa)
            cout << "MAYBE" << endl;
        else
            YES;
    }
}

C. Sofia and the Lost Operations

題意

C. 索菲亞和失落的操作
每個測試的時間限制:2秒
每個測試的記憶體限制:256兆位元組
輸入:標準輸入
輸出:標準輸出

索菲亞有一個由 n 個整數 a1, a2, ..., an 組成的陣列。有一天,她對這個陣列感到厭倦,於是決定依次對它進行 m 次修改操作。

每個修改操作都由一對數字 ⟨cj, dj⟩ 來描述,這意味著陣列中索引為 cj 的元素應賦值為 dj,即執行賦值 acj=dj。在依次執行所有修改操作後,索菲亞丟棄了得到的陣列。

最近,你發現了一個由 n 個整陣列成的陣列 b1, b2, ..., bn。你想知道這個陣列是否是索菲亞的陣列。你知道原始陣列的值以及 d1, d2, ..., dm 的值。結果發現數值 c1, c2, ..., cm 丟失了。

是否存在一個序列 c1, c2, ..., cm 使得對陣列 a1, a2, ..., an 的修改操作 ⟨c1, d1⟩, ⟨c2, d2⟩, ..., ⟨cm, dm⟩ 的順序應用可以將其轉換為陣列 b1, b2, ..., bn 呢?

輸入

第一行包含一個整數 t(1≤t≤104)——測試用例的數量。

然後是測試用例的說明。

每個測試用例的第一行都包含一個整數 n(1≤n≤2⋅105)——陣列的大小。

每個測試用例的第二行包含 n 個整數 a1, a2, ..., an(1≤ai≤109)——原始陣列的元素。

每個測試用例的第三行包含 n 個整數 b1, b2, ..., bn(1≤bi≤109)——找到的陣列的元素。

第四行包含一個整數 m(1≤m≤2⋅105)——修改操作的次數。

第五行包含 m 個整數 d1, d2, ..., dm(1≤dj≤109)——每次修改操作的保留值。

保證所有測試用例中 n 的值之和不超過 2⋅105,同樣,所有測試用例中 m 的值之和不超過 2⋅105。

輸出

輸出 t 行,每一行都是相應測試用例的答案。如果存在合適的序列 c1, c2, ..., cm,則輸出 "YES",否則輸出 "NO"。

您可以在任何情況下輸出答案(例如,字串 "yEs"、"yes"、"Yes" 和 "YES" 將被識別為肯定答案)。

示例

輸入

7
3
1 2 1
1 3 2
4
1 3 1 2
4
1 2 3 5
2 1 3 5
2
2 3
5
7 6 1 10 10
3 6 1 11 11
3
4 3 11
4
3 1 7 8
2 2 7 10
5
10 3 2 2 1
5
5 7 1 7 9
4 10 1 2 9
8
1 1 9 8 7 2 10 4
4
1000000000 203 203 203
203 1000000000 203 1000000000
2
203 1000000000
1
1
1
5
1 3 4 5 1

輸出

YES
NO
NO
NO
YES
NO
YES

解題思路

檢查\(a\)\(b\)在同一位置不同值的每一個\(b_i\)是否都存在與\(d\)中。

注:\(d\)中最後一個位置的值一定要是\(b\)的任意一個值。

題解

void solve()
{
    int n;
    cin >> n;
    vi a(n);
    vi b(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++)
    {
        cin >> b[i];
    }
    int m;
    cin >> m;
    vi d(m);
    mii mp;
    for (int i = 0; i < m; i++)
    {
        cin >> d[i];
        mp[d[i]]++;
    }
    bool flag1 = true;
    bool flag2 = false;
    for (int i = 0; i < n; i++)
    {
        if (b[i] == d[m - 1])
            flag2 = true;
        if (a[i] != b[i])
        {
            if (mp[b[i]])
                mp[b[i]]--;
            else
                flag1 = false;
        }
    }
    if (flag1 && flag2)
        YES;
    else
        NO;
}

D. GCD-sequence

噁心的大模擬

題意

D. GCD序列
每個測試的時間限制:2秒
每個測試的記憶體限制:256兆位元組
輸入:標準輸入
輸出:標準輸出

兩個整數 x 和 y 的 GCD(最大公約數)是 z,可以整除 x 和 y 的最大整數。例如,GCD(36,48)=12,GCD(5,10)=5 和 GCD(7,11)=1。

克里斯蒂娜有一個由 n 個正整陣列成的陣列 a。她想透過計算每一對相鄰數字的 GCD 得到一個新陣列 b,稱為 GCD 序列。

因此,GCD 序列 b 中的元素將使用公式 bi=GCD(ai,ai+1) 計算,1≤i≤n−1。

確定是否有可能從陣列 a 中刪除恰好一個數字,從而使 GCD 序列 b 不遞減(即 bi≤bi+1 始終為真)。

例如,假設克里斯蒂娜有一個陣列 a = [20,6,12,3,48,36]。如果她從中刪除 a4=3,並計算 b 的 GCD 序列,她會得到:

  • b1=GCD(20,6)=2
  • b2=GCD(6,12)=6
  • b3=GCD(12,48)=12
  • b4=GCD(48,36)=12

得到的 GCD 序列 b = [2,6,12,12] 是不遞減的,因為 b1≤b2≤b3≤b4。

輸入

第一行輸入資料包含一個數字 t (1≤t≤10^4) - 測試用例的數量。

隨後是測試用例的描述。

每個測試用例的第一行包含一個整數 n (3≤n≤2⋅10^5) - 陣列 a 中的元素個數。

每個測試用例的第二行包含 n 個整數 ai (1≤ai≤10^9) - 陣列 a 中的元素。

保證所有測試用例中 n 的總和不超過 2⋅10^5。

輸出

為每個測試用例輸出一行:

  • 如果能從陣列 a 中刪除一個數字,使 b 的 GCD 序列不遞減,則輸出 "YES";
  • 否則輸出 "NO"。

您可以在任何情況下輸出答案(例如,字串 "yEs"、"yes"、"Yes" 和 "YES" 都會被識別為肯定答案)。

示例

輸入

12
6
20 6 12 3 48 36
4
12 6 3 4
3
10 12 3
5
32 16 8 4 2
5
100 50 2 10 20
4
2 4 8 1
10
7 4 6 2 4 5 1 4 2 8
7
5 9 6 8 5 9 2
6
11 14 8 12 9 3
9
5 7 3 10 6 3 12 6 3
3
4 2 4
8
1 6 11 12 6 12 3 6

輸出

YES
NO
YES
NO
YES
YES
NO
YES
YES
YES
YES
YES

解題思路

預處理出\(b\)中的遞減序列,然後列舉每一個位置,檢查一下這些遞減序列是否變成非遞減的就行

題解

void solve()
{
    int n;
    cin >> n;
    vi a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    if (n == 3)
    {
        YES;
        return;
    }
    vi b;
    for (int i = 0; i < n - 1; i++)
    {
        b.pb(__gcd(a[i], a[i + 1]));
    }
    mii wrong;
    for (int i = 0; i < n - 2; i++)
    {
        if (b[i] > b[i + 1])
            wrong[i]++;
    }
    if (wrong.size() == 0)
    {
        YES;
        return;
    }
    bool flag = false;
    for (int i = 0; i < n; i++)
    {
        if (i == 0)
        {
            if (b[i] > b[i + 1] && (int)wrong.size() == 1)
                flag = true;
        }
        else if (i == n - 1)
        {
            if (b[i - 2] > b[i - 1] && (int)wrong.size() == 1)
                flag = true;
        }
        else
        {
            int loss = __gcd(a[i - 1], a[i + 1]);
            if (i - 2 >= 0 && loss < b[i - 2])
                continue;
            if (i + 1 < n - 1 && b[i + 1] < loss)
                continue;
            int len = 0;
            if (i - 2 >= 0 && b[i - 2] > b[i - 1])
                len++;
            if (i <= n - 2 && b[i - 1] > b[i])
                len++;
            if (i + 1 <= n - 2 && b[i] > b[i + 1])
                len++;
            if (wrong.size() - len == 0)
                flag = true;
        }
    }
    if (flag)
        YES;
    else
        NO;
}

E. Permutation of Rows and Columns

題意

E. 行和列的排列

題目描述

給你一個大小為 n 乘 m 的矩陣 a,其中包含從 1 到 n⋅m 的整數排列。

一個由 n 個整陣列成的排列是一個陣列,其中包含了從 1 到 n 的所有整數。例如,陣列 [1]、[2,1,3]、[5,4,3,2,1] 是排列,而陣列 [1,1]、[100]、[1,2,4,5] 不是排列。

如果一個矩陣的所有元素都寫出後,得到的陣列是一個排列,那麼這個矩陣就包含一個排列。矩陣 [[1,2],[3,4]]、[[1]]、[[1,5,3],[2,6,4]] 包含排列,而矩陣 [[2]]、[[1,1],[2,2]]、[[1,2],[100,200]] 不包含排列。

您可以在一次操作中執行以下兩個操作之一:

  1. 選擇列 c 和 d (1≤c,d≤m, c≠d) 並交換這些列;
  2. 選擇行 c 和 d (1≤c,d≤n, c≠d) 並交換這些行。

您可以執行任意數量的操作。

給你原始矩陣 a 和矩陣 b。您的任務是確定是否有可能透過給定的運算將矩陣 a 變換成矩陣 b。

輸入

第一行包含一個整數 t (1≤t≤10^4) - 測試用例的數量。下面是測試用例的說明。

每個測試用例描述的第一行包含 2 個整數 n 和 m (1≤n,m≤n⋅m≤2⋅10^5) - 矩陣的大小。

接下來的 n 行分別包含 m 個整數 aij (1≤aij≤n⋅m)。可以保證矩陣 a 是一個排列。

接下來的 n 行分別包含 m 個整數 bij (1≤bij≤n⋅m)。可以保證矩陣 b 是一個排列。

保證所有測試用例的值 n⋅m 之和不超過 2⋅10^5。

輸出

對於每個測試用例,如果可以從第一個矩陣得到第二個矩陣,則輸出 "YES",否則輸出 "NO"。

您可以以任何大小寫(小寫或大寫)輸出每個字母。例如,字串 "yEs"、"yes"、"Yes "和 "YES "將被視為肯定答案。

示例

輸入

7
1 1
1
1
2 2
1 2
3 4
4 3
2 1
2 2
1 2
3 4
4 3
1 2
3 4
1 5 9 6
12 10 4 8
7 11 3 2
1 5 9 6
12 10 4 8
7 11 3 2
3 3
1 5 9
6 4 2
3 8 7
9 5 1
2 4 6
7 8 3
2 3
1 2 6
5 4 3
6 1 2
3 4 5
1 5
5 1 2 3 4
4 2 5 1 3

輸出

YES
YES
NO
YES
YES
NO
YES

在第二個例子中,原始矩陣如下所示:

1 3
2 4

交換行 1 和 2 後,矩陣變為:

3 1
4 2

交換 1 和 2 列後,它就等於矩陣 b:

4 2
3 1

解題思路

很容易就可以觀察到,無論怎麼進行交換,每一行擁有的數字都不會變,只是位置改變了,對於每一列同樣也是如此。所以只需要逐行和逐列的去檢查\(b\)矩陣的一行或一列對應的數字集合是否在\(a\)中出現即可。

題解

void solve()
{
    int n, m;
    cin >> n >> m;
    vector<vi> a(n, vi(m));
    vector<vi> b(n, vi(m));
    map<vi, int> mp_col;
    for (int i = 0; i < n; i++)
    {
        vi temp;
        for (int j = 0; j < m; j++)
        {
            cin >> a[i][j];
            temp.eb(a[i][j]);
        }
        sort_all(temp);
        mp_col[temp]++;
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> b[i][j];
        }
    }
    for (int i = 0; i < n; i++)
    {

        vi temp;
        for (int j = 0; j < m; j++)
        {
            temp.eb(b[i][j]);
        }
        sort_all(temp);
        if (mp_col[temp] == 0)
        {
            NO;
            return;
        }
    }
    map<vi, int> mp_row;
    for (int j = 0; j < m; j++)
    {
        vi temp;
        for (int i = 0; i < n; i++)
        {
            temp.eb(a[i][j]);
        }
        sort_all(temp);
        mp_row[temp]++;
    }
    for (int j = 0; j < m; j++)
    {
        vi temp;
        for (int i = 0; i < n; i++)
        {
            temp.eb(b[i][j]);
        }
        sort_all(temp);
        if (mp_row[temp] == 0)
        {
            NO;
            return;
        }
    }
    YES;
}

F1. Field Division (easy version)

題意

Alice 和 Bob 正在分割田地。田地是一個大小為 n×m(2≤n,m≤10^9)的矩形,行從上到下編號為 1 到 n,列從左到右編號為 1 到 m。行和列的交叉處的單元格用 (r,c) 表示。

Bob 有 k(2≤k≤2⋅10^5)個噴泉,它們都位於田地的不同單元格中。Alice 負責分割田地,但她必須滿足幾個條件:

  • 要分割田地,Alice 將從田地左側或上側的任意空閒(無噴泉)單元格開始移動,每次移動都會移動到相鄰的下或右單元格。她的路徑將在場地的右側或底側結束。
  • Alice 的路徑將區域分為兩部分 — 一部分將屬於 Alice(這部分包括她路徑上的單元格),另一部分將屬於 Bob。
  • Alice 將擁有包含單元格 (n,1) 的部分。
  • Bob 將擁有包含單元格 (1,m) 的部分。

Alice 希望以這樣一種方式分割田地,以獲得儘可能多的單元格。

Bob 希望保留所有噴泉的所有權,但他可以將其中一個噴泉交給 Alice。首先,輸出整數 α — 如果 Bob 不給 Alice 任何噴泉(即所有噴泉都保留在 Bob 的地塊上),Alice 可以擁有的地塊的最大面積。然後輸出 k 個非負整數 a1,a2,…,ak,其中:

  • ai=0,如果 Bob 給了 Alice 第 i 個噴泉後,與所有 k 個噴泉都屬於 Bob 的情況相比,Alice 的地塊的最大可能大小沒有增加;
  • ai=1,如果 Bob 給了 Alice 第 i 個噴泉,那麼與所有 k 個噴泉都屬於 Bob 的情況相比,Alice 的地塊的最大可能大小會增加。

輸入

第一行包含一個整數 t(1≤t≤10^4) - 測試用例數。

每個測試用例的第一行包含三個整數 n、m 和 k(2≤n,m≤10^9, 2≤k≤2⋅10^5)-- 欄位大小和噴泉數量。

接下來是 k 行,每行包含兩個數字 ri 和 ci(1≤ri≤n, 1≤ci≤m)-- 即帶有第 i 個噴泉的單元格的座標。保證所有單元格都是不同的,沒有一個單元格是 (n,1)。

保證所有測試用例的 k 之和不超過 2⋅10^5。

輸出

對於每個測試案例,首先輸出 α - 如果 Bob 不給 Alice 任何噴泉,Alice 可以擁有的地塊的最大面積。然後輸出 k 個非負整數 a1,a2,…,ak,其中:

  • ai=0,如果 Bob 給了 Alice 第 i 個噴泉後,與所有 k 個噴泉都屬於 Bob 的情況相比,Alice 的地塊的最大可能大小沒有增加;
  • ai=1,如果 Bob 給了 Alice 第 i 個噴泉,那麼與所有 k 個噴泉都屬於 Bob 的情況相比,Alice 的地塊的最大可能大小會增加。

如果你輸出任何其他適合 64 位有符號整數型別的正數代替 1,它也會被識別為 1。因此,這個問題的難解版本也能透過簡單版本的測試。

示例

輸入

5
2 2 3
1 1
1 2
2 2
5 5 4
1 2
2 2
3 4
4 3
2 5 9
1 2
1 5
1 1
2 2
2 4
2 5
1 4
2 3
1 3
6 4 4
6 2
1 3
1 4
1 2
3 4 5
2 1
3 2
1 4
1 3
2 4

輸出

1
1 0 1 
11
0 1 0 1 
1
0 0 1 1 0 0 0 0 0 
6
1 0 0 0 
1
1 1 0 0 0 

以下是第二個示例的圖片:

image-20240604023914297

噴泉的指數用綠色標出。屬於 Alice 的單元格用藍色標出。

請注意,如果 Bob 給了 Alice 噴泉 1 或噴泉 3,那麼該噴泉就不可能出現在 Alice 的地塊上。

解題思路

我們只需要對噴泉按行座標排個序,然後進行列舉即可,列舉的時候要維護一下上限。

題解

struct fountain
{
    ll x, y, idx;
};
bool cmp(fountain a, fountain b)
{
    if (a.x != b.x)
        return a.x < b.x;
    return a.y < b.y;
};
void solve()
{
    ll n, m, k;
    cin >> n >> m >> k;
    vl x(k + 1);
    vl y(k + 1);
    for (int i = 1; i <= k; i++)
    {
        cin >> x[i] >> y[i];
    }
    vector<fountain> founs;
    for (int i = 1; i <= k; i++)
    {
        founs.pb({n - x[i] + 1, y[i], i});
    }
    sort(all(founs), cmp);
    vpll temp;
    ll mn = INFLL;
    ll ans = 0;
    for (int i = 0; i < k; i++)
    {
        bool flag = false;
        if (i == 0)
            flag = true;
        else if (founs[i].y < mn)
            flag = true;
        if (flag)
        {
            temp.pb({x[founs[i].idx], founs[i].y});
            x[founs[i].idx] = 1;
            mn = founs[i].y;
        }
        else
            x[founs[i].idx] = 0;
    }
    if (temp[0].ft != n)
        ans += (n - temp[0].ft) * m;
    temp.pb({0, 0});
    for (int i = 0; i < temp.size() - 1; ++i)
    {
        ans += (temp[i].ft - temp[i + 1].ft) * (temp[i].sd - 1);
    }
    cout << ans << endl;
    for (int i = 1; i <= k; i++)
    {
        cout << x[i] << ' ';
    }
    cout << endl;
}

相關文章