1. 程式人生 > 其它 >AcWing第9場周賽題解

AcWing第9場周賽題解

A. 3778. 平衡陣列

題目連結:https://www.acwing.com/problem/content/3781/

題目大意:\(m\) 次題目要求的操作使最終所有數都相等。

解題思路:思維題。將所有元素加上 \(i\) 等價於將這個數減去 \(i\)。所以一種必定可行的方案就是一次操作第 \(2, 3, \ldots, n\)

示例程式:

#include <bits/stdc++.h>
using namespace std;

int T, n;

int main() {
    cin >> T;
    while (T--) {
        cin >> n;
        cout << n-1 << endl;
        for (int i = 2; i <= n; i++) {
            if (i > 2) cout << " ";
            cout << i;
        }
        cout << endl;
    }
    return 0;
}

B. 3779. 相等的和

題目連結:https://www.acwing.com/problem/content/3782/

題目大意:略。

解題思路:列舉。先求出每個序列的和,設第 \(i\) 個數列的元素和為 \(sum_i\),然後對於 第 \(i\) 個數列中的數值為 \(x\) 的元素,刪除 \(x\) 後數列中剩餘元素和為 \(sum_i - x\),判斷 \(sum_i - x\) 在別的數列中是否存在(用 map),如果如在一個 \(sum_j - y = sum_i - x\),則答案就找到了。

示例程式:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int k, n, a[maxn];
map<int, pair<int, int>> mp;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> k;
    for (int i = 1; i <= k; i++) {
        cin >> n;
        int sum = 0;
        for (int j = 1; j <= n; j++) {
            cin >> a[j];
            sum += a[j];
        }
        for (int j = 1; j <= n; j++) {
            if (mp.find(sum - a[j]) != mp.end()) {
                pair<int, int> v = mp[sum - a[j]];
                if (v.first != i) {
                    cout << "YES" << endl;
                    cout << v.first << " " << v.second << endl;
                    cout << i << " " << j << endl;
                    return 0;
                }
            }
            else
                mp[sum - a[j]] = {i, j};
        }
    }
    cout << "NO" << endl;
    return 0;
}

題目連結:

題目大意:

解題思路:(下面說的遞增/遞減指的都是非嚴格單調遞增/遞減)

考慮到最終的數列只有如下三種情況:

  1. 全部遞增;
  2. 全部遞減;
  3. 先遞增再遞減。

所以可以定義狀態 \(f_{1,i}\) 表示區間 \([1,i]\) 遞增的情況下的最大和,\(f_{2,i}\) 表示區間 \([i,n]\) 遞減的情況下的最大和,則答案為 \(\max\{ f_{1,i} + f_{2,i+1} \}\)

實現時可以使用 單調佇列 優化。

示例程式:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
int n;
long long a[maxn], f1[maxn], f2[maxn];
deque<int> que;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    // 先從前往後求 f1[i]
    for (int i = 1; i <= n; i++) {
        while (!que.empty() && a[que.back()] > a[i]) que.pop_back();
        int p = que.empty() ? 0 : que.back();
        f1[i] = f1[p] + (i - p) * a[i];
        que.push_back(i);
    }
    // 再從後往前求 f2[i]
    que.clear();
    for (int i = n; i >= 1; i--) {
        while (!que.empty() && a[que.back()] > a[i]) que.pop_back();
        int p = que.empty() ? (n+1) : que.back();
        f2[i] = f2[p] + (p - i) * a[i];
        que.push_back(i);
    }
    int x = 1;  // 最大值下標
    for (int i = 2; i <= n; i++)
        if (f1[i] + f2[i] - a[i] > f1[x] + f2[x] - a[x])
            x = i;
    long long y = a[x];
    for (int i = x-1; i >= 1; i--) y = a[i] = min(y, a[i]);
    y = a[x];
    for (int i = x+1; i <= n; i++) y = a[i] = min(y, a[i]);
    for (int i = 1; i <= n; i++) {
        if (i > 1) cout << " ";
        cout << a[i];
    }
    cout << endl;
    return 0;
}