Codeforces 1257E - The Contest

題意
三我的,每一個人有一些數字,組合起來是\(1\)-\(n\),每一個人能夠給另外一我的一個擁有的數字,問最小操做數,使得第一我的擁有\(1\)-\(i\)的數,第二我的擁有\(i+1\)-\(j\)的數,第三我的擁有\(j+1\)~\(n\)的數,即第一我的爲前綴,第二我的爲中間部分,第三我的爲後綴。
注意:能夠有一個或兩我的最後不擁有數字。ios

分析
看到三我的操做,咱們先看兩我的操做時的狀況:
假設到最後,第一我的擁有\(1\)-\(i\),第二我的擁有\(i+1\)-\(n\),那麼最小操做數爲第二我的\(1\)-\(i\)中擁有的數字加上第一我的\(i+1\)-\(n\)中擁有的數字。咱們能夠採用前綴和,\(cnt1[k]\)表示第一我的前\(k\)個數中擁有的個數,\(cnt2[k]\)表示第二我的前\(k\)個數中擁有的個數,則表達式爲:$$cnt2[i]+cnt1[n]-cnt1[i]$$受到啓發咱們看三我的操做時的狀況:
假設到最後,第一我的擁有\(1\)-\(i\),第二我的擁有\(i+1\)~\(j\),第三我的擁有\(j+1\)-\(n\),那麼最小操做數爲第二我的和第三我的\(1\)-\(i\)中擁有的個數加上第一我的和第三我的\(i+1\)-\(j\)中擁有的個數加上第一我的和第二我的\(j+1\)-\(n\)中擁有的個數。咱們能夠採用前綴和,\(cnt1[k]\)表示第一我的前\(k\)個數中擁有的個數,\(cnt2[k]\)表示第二我的前\(k\)個數中擁有的個數,\(cnt3[k]\)表示第三我的前\(k\)個數中擁有的個數字表達式爲:$$cnt2[i]+cnt3[i]+cnt1[j]-cnt1[i]+cnt3[j]-cnt3[i]+cnt1[n]-cnt1[j]+cnt2[n]-cnt2[j]$$化簡獲得:$$cnt2[i]-cnt1[i]+cnt3[j]-cnt2[j]+cnt1[n]+cnt2[n]$$咱們從\(0\)-\(n\)枚舉\(i\),接下來咱們考慮\(j\)的取值,咱們能夠看到對於固定的\(i\),只須要找到一個\(j\)使得該式子最小便可,那麼咱們能夠設置一個後綴\(minn[]\)數組,\(minn[i]\)表示當\(i\leq j\leq n\)時,\(cnt3[j]-cnt2[j]\)最小的值,那麼答案即爲:$$cnt2[i]-cnt1[i]+minn[i]+cnt1[n]+cnt2[n]$$
代碼c++

#pragma GCC optimize(3, "Ofast", "inline")

#include <bits/stdc++.h>

#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define LL long long
using namespace std;
const int maxn = (ll) 2e5 + 5;
const int mod = 1000000007;
const int inf = 0x3f3f3f3f;
int cnt1[maxn], cnt2[maxn], cnt3[maxn];
int minn[maxn];
vector<int> v1, v2, v3;

int main() {
    start;
    int k1, k2, k3;
    cin >> k1 >> k2 >> k3;
    v1.resize(k1 + 5);
    v2.resize(k2 + 5);
    v3.resize(k3 + 5);
    /*輸入並標記*/
    for (int i = 1; i <= k1; ++i) {
        cin >> v1[i];
        ++cnt1[v1[i]];
    }
    for (int i = 1; i <= k2; ++i) {
        cin >> v2[i];
        ++cnt2[v2[i]];
    }
    for (int i = 1; i <= k3; ++i) {
        cin >> v3[i];
        ++cnt3[v3[i]];
    }
    int n = k1 + k2 + k3;
    for (int i = 1; i <= n; ++i) {//前綴和
        cnt1[i] = cnt1[i - 1] + cnt1[i];
        cnt2[i] = cnt2[i - 1] + cnt2[i];
        cnt3[i] = cnt3[i - 1] + cnt3[i];
    }
    /*如分析*/
    for (int i = 0; i <= n; ++i)
        minn[i] = cnt3[i] - cnt2[i];
    for (int i = n - 1; i >= 0; --i)
        minn[i] = min(minn[i + 1], minn[i]);
    int ans = inf;
    for (int i = 0; i <= n; ++i) {
        int t = cnt2[i] - cnt1[i] + minn[i] + cnt1[n] + cnt2[n];
        ans = min(ans, t);
    }
    cout << ans;
    return 0;
}

本場比賽\(D\)\(E\)慘痛教訓:玩後綴必定要注意邊界!!!
如有問題可在評論區提出,謝謝。數組

相關文章
相關標籤/搜索