Educational Codeforces Round 172 Solution

~清渠~發表於2024-12-03

A. Greedy Monocarp

題目大意

有N個箱子,第i個箱子裡有Ai個硬幣,有一個人會從多到少拿這些箱子。

現在你可以給一個箱子加若干硬幣,請你使這個人可以拿到剛好K個硬幣時停下拿箱子,要求加入的硬幣數量儘量少。

解題思路

排個序,然後從大到小加,加到剛好不能再多加一個箱子為止,結果就是K-sum。

void solve()
{
    int n, k;
    cin >> n >> k;
    vi v(n);
    fore(i, v) cin >> i;
    sort(all(v));
    reverse(all(v));

    int sum = 0;
    rep(i, n) {
        sum += v[i];
        if (sum >= k) break;
        if (i != n - 1)
            if (sum < k && sum + v[i + 1] > k) {
                cout << k - sum << endl;
                return;
            }
    }
    cout << k - sum << endl;
}


B. Game with Colored Marbles

題目大意

兩個人玩遊戲,桌子上有N個不同顏色的彈珠,他們可以輪流選擇彈珠拿走,最後拿完的時候記分,積分規則如下:

  • 有一個不同顏色的彈珠加一分
  • 完全拿完了一種顏色的彈珠加一分

兩個人都採取最佳策略,問Alice最後的分數。

解題思路

對於單個的彈珠兩個人肯定是輪流拿,剩下的彈珠Alice都能搶到一個。

int cnt[1005];
void solve()
{
    int n;
    cin >> n;

    vi v(n);
    memset(cnt, 0, sizeof(cnt));
    fore(i, v) {
        cin >> i;
        cnt[i]++;
    }
    int cnt1 = 0, cnt2 = 0;
    repo(i, 1000) {
        if (cnt[i] == 1) cnt1++;
        else if (cnt[i] != 0) cnt2++;
    }
    int ans = (cnt1 + 1) / 2 * 2 + cnt2;
    cout << ans << endl;
}

C. Competitive Fishing

題目大意

有一個序列,0表示Alice,1表示Bob,你可以把整個序列分成m段,對於第一段的積分為0,第二段積分為1,第三段積分為3...,兩個人分別根據01在哪個段內加分。

現在Bob想領先Alice至少k分,問最少要分多少段(分段方式自選)

解題思路

考慮在某個位置劃一刀帶來的貢獻,貢獻就是字尾所有的位置的積分都會+1,那麼Bob領先的差值就會增加字尾1的個數減去字尾0的個數。

那麼對於每個位置都計算一下字尾1的個數減去0的個數,然後排個序算最少要劃幾刀就可以了。

int cnt[1005];
void solve()
{
    int n;
    cin >> n;

    vi v(n);
    memset(cnt, 0, sizeof(cnt));
    fore(i, v) {
        cin >> i;
        cnt[i]++;
    }
    int cnt1 = 0, cnt2 = 0;
    repo(i, 1000) {
        if (cnt[i] == 1) cnt1++;
        else if (cnt[i] != 0) cnt2++;
    }
    int ans = (cnt1 + 1) / 2 * 2 + cnt2;
    cout << ans << endl;
}

D. Recommendations

題目大意

有N個區間,一個區間如果完全包含另一個區間,那麼就被稱作是這個區間的predictor,求每個區間的所有predictor的相同覆蓋段長度。

解題思路

顯然相同覆蓋段長度是這些predictor的最小的R-最大的L,那麼就是一個二維數點,求以LR為XY軸的二維平面內,左上角的區域中最小的R和最大的L。

程式碼從X軸掃的,其實掃Y軸更方便。

const int m = 1e9 + 2;

int n, s[200005];

struct su {
    int x, y, id;
    bool operator<(const su& temp)const {
        if (x == temp.x) return y > temp.y;
        return x < temp.x;
    }
}a[200005];
int ans[200005];

void add(int x, int v) {
    for (;x <= n;x += x & -x) s[x] = max(s[x], v);
}

int ask(int x) {
    int res = 0;
    for (;x;x -= x & -x) res = max(s[x], res);
    return res;
}

void solve()
{
    cin >> n;
    set<int> q;
    vector<int> f;
    unordered_map<int, int> mp;
    for (int i = 1;i <= n;++i) {
        int x, y;
        cin >> x >> y;
        a[i].x = x;
        a[i].y = y;
        a[i].id = i;
        f.push_back(a[i].y);
        s[i] = 0;
    }
    sort(all(f));
    reverse(all(f));
    unique(all(f));
    for (int i = 0;i < f.size();++i) {
        if (i > 0 && (f[i] > f[i - 1])) break;
        mp[f[i]] = i + 1;
    }
    sort(a + 1, a + n + 1);
    repo(i, n) {
        if (i > 1) {
            q.insert(a[i - 1].y);
            add(mp[a[i - 1].y], a[i - 1].x);
        }
        if ((i > 1 && a[i].x == a[i - 1].x && a[i].y == a[i - 1].y) || (i < n && a[i].x == a[i + 1].x && a[i].y == a[i + 1].y)) {
            ans[a[i].id] = 0;
            continue;
        }
        auto xx = q.lower_bound(a[i].y);
        if (xx == q.end()) {
            ans[a[i].id] = 0;
            continue;
        }
        int y = ask(mp[a[i].y]);
        if (y == 0 || (*xx) < y) {
            ans[a[i].id] = 0;
            continue;
        }
        ans[a[i].id] = (*xx) - y - (a[i].y - a[i].x);

    }
    repo(i, n) {
        cout << ans[i] << "\n";
    }
}

相關文章