Pinely Round 4 (Div. 1 + Div. 2)

Sakura17發表於2024-08-04

題目連結:Pinely Round 4 (Div. 1 + Div. 2)

總結:被B卡了一年。

A. Maximize the Last Element

tag:模擬

Description:給定一個長度為奇數的陣列,每次可以刪除兩個相鄰的元素,直到剩下一個元素為止,求該元素的最大值。

Solution:模擬發現之後保留奇數位的值。

void solve(){
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i ++)
        cin >> a[i];
    
    int ans = 0;
    for (int i = 0; i < n; i += 2)
        ans = max(ans, a[i]);

    cout << ans << endl;
}

B. AND Reconstruction

tag:構造

Description:給定一個長為\(n - 1\)的陣列\(b\),構造一個長度為\(n\)的陣列\(a\),滿足\(a_i \& a_{i + 1} == b_i\),否則輸出\(-1\)

Solution:我們令\(a_1 == b_1\)。然後我們發現\(a_i\)會影響\(b_i\)\(b_{i - 1}\),那麼\(a_i\)包含最少的\(1\)時,必須為\(b_{i - 1} | b_i\)。最後我們令\(a_n == b_{n - 1}\)

Competing:一開始就想到了,但是思路不清晰,氣。

void solve(){
    cin >> n;
    vector<int> b(n), a(n);
    for (int i = 0; i < n - 1; i ++){
        cin >> b[i];
    }
    a[0] = b[0];
    for (int i = 1; i < n - 1; i ++){
        a[i] = b[i] | b[i - 1];
    }
    a[n - 1] = b[n - 2];
    for (int i = 0; i < n - 1; i ++){
        if (b[i] != (a[i] & a[i + 1])){
            cout << -1 << endl;
            return;
        }
    }

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

C. Absolute Zero

tag:構造

Description:給定一個長度為\(n\)的陣列,每次操作可以選定一個\(x\),將\(a_i\)更新為\(|a_i - x|\)。構造一個操作序列不操作\(40\)次,使陣列\(a\)全為\(0\).

Solution:模擬幾組樣例發現,如果陣列中所有元素的奇偶性必須相同,否則當一個數變為奇數,另一個數會變成偶數。(開始時這兩個數奇偶性不同)。

  • 我們只需要每次減去\((r + l) / 2\),逐漸縮小上界即可。
  • 可以使用\(2^{31}, 2^{30}, ... 1\)。逐漸縮小上界。

Competing:將\(r +l\)寫為\(r - l\)

void solve(){
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i ++){
        cin >> a[i];
    }
    sort(a.begin(), a.end());
    for (int i = 1; i < n; i ++){
        if ((a[i] - a[i - 1]) & 1){
            cout << -1 << endl;
            return;
        }
    }
    if (a[0] == a[n - 1]){
        if (a[0] == 0){
            cout << 0 << endl << endl;
            return;
        }
        cout << 1 << endl;
        cout << a[0] << endl;
        return;
    }

    vector<int> ans;
    while (a[0] != a[n - 1]){
        int t = (a[n - 1] + a[0]) / 2;
        ans.eb(t);
        for (int i = 0; i < n; i ++){
            a[i] = abs(a[i] - t);
        }
        sort(a.begin(), a.end());
    }
    if (a[0] != 0)
        ans.eb(a[0]);
    cout << ans.size() << endl;
    for (int i = 0; i < ans.size(); i ++)
        cout << ans[i] << " \n"[i + 1 == ans.size()];

}

D. Prime XOR Coloring

tag:構造

四色定理:“將平面任意地細分為不相重疊的區域,每一個區域總可以用1234這四個數字之一來標記而不會使相鄰的兩個區域得到相同的數字。”這裡所指的相鄰區域是指有一整段邊界是公共的。如果兩個區域只相遇於一點或有限多點就不叫相鄰的。

Description:有\(n\)個頂點,編號從\(1\)\(n\),當\(u \oplus v\)為質數時,\(u\)\(v\)之間有一條邊。用最少的顏色給所有頂點染色,要求相鄰頂點的顏色不能相同。

Solution:考慮哪些點之間連邊太難,考慮哪些點之間不連邊。

  • 根據四色定理知,當\(n >= 6\)時,一定需要四種顏色。
  • 考慮所有質數,發現除了\(2\)都是奇數。\(2\)的二進位制\(01\)\(3\)的二進位制\(10\)\(4\)的二進位制\(00\)。那麼我們對\(4\)取餘,\(mod4\)相同的數異或之後一定不是質數。
  • 然後特判\(n <= 5\)
void solve(){
    cin >> n;
    if (n == 1){
        cout << 1 << endl << 1 << endl;
    }
    else if (n == 2){
        cout << 2 << endl;
        cout << 1 << " " << 2 << endl;
    }
    else if (n == 3){
        cout << 2 << endl;
        cout << "1 2 2\n";
    }
    else if (n == 4){
        cout << 3 << endl;
        cout << "1 2 2 3\n";
    }
    else if (n == 5){
        cout << 3 << endl;
        cout << "1 2 2 3 3\n";
    }
    else{
        cout << 4 << endl;
        for (int i = 1; i <= n; i ++){
            cout << (i % 4) + 1 << " \n"[i == n];
        }
    }
}

E. Coloring Game

tag:二分圖 + 互動

Description:給定一個圖,一共\(n\)輪操作,每輪操作:

  • \(Alice\)選擇三個顏色中選擇兩個顏色(\(1, 2, 3\))。
  • \(Bob\)選擇一個未染色的頂點進行染色。
  • 如果存在相鄰頂點顏色相同\(Alice\)贏,否則\(Bob\)贏。
  • 你需要選擇玩家,並給出獲勝策略。

Solution:顯然\(Alice\)想贏每次給出兩個相同的顏色最好。模擬一下發現如果是二分圖則\(Bob\)必贏,否則\(Alice\)必贏。

  • 如果不是二分圖,\(Alice\)獲勝,每次輸出\(1, 2\)即可。
  • 如果是二分圖\(Bob\)獲勝,先用\(1\)或者\(2\)將其中一種顏色染完,剩下的一種用\(3\)進行染色。因為\(1\)的個數加\(2\)的個數等於\(n\),因此必定有一種顏色會被染完。
void solve(){
    cin >> n >> m;
    vector g(n, vector<int>());
    vector st(n, -1);

    for (int i = 0; i < m; i ++){
        int x, y;
        cin >> x >> y;
        x --, y --;
        g[x].eb(y);
        g[y].eb(x);
    }
    
    bool flag = true;
    vector<int> f1, f2;
    auto dfs = [&](auto self, int x, int fa, int c) -> void {
        st[x] = c;
        if (c == 1){
            f1.eb(x);
        }
        else
            f2.eb(x);
        for (auto i : g[x]){
            if (i == fa)
                continue;
            if (st[i] == -1){
                self(self, i, x, !c);
            }
            else{
                if (st[i] == c){
                    flag = false;
                }
            }
        }
    };
    dfs(dfs, 0, -1, 1);
    if (flag){
        cout << "Bob" << endl;
        int s1 = f1.size(), s2 = f2.size();
        for (int i = 0; i < n; i ++){
            int a, b;
            cin >> a >> b;
            if (a > b)
                swap(a, b);
            if (a == 1){
                if (s1){
                    s1 --;
                    cout << f1.back() + 1 << " " << a << endl;
                    f1.pop_back();
                }
                else{
                    s2 --;
                    cout << f2.back() + 1 << " " << b <<  endl; 
                    f2.pop_back();
                }
            }
            if (a == 2){
                if (s2){
                    s2 --;
                    cout << f2.back() + 1 << " " << a <<  endl;
                    f2.pop_back();
                }
                else{
                    s1 --;
                    cout << f1.back() + 1 << " " << b << endl;
                    f1.pop_back();
                }
            }
        }
    }
    else{
        cout << "Alice" << endl;
        for (int i = 1; i <= n; i ++){
            int a, b;
            cout << "1 2" << endl;
            cin >> a >> b;
        }
    }
}

相關文章