Educational Codeforces Round 91 (Rated for Div. 2)

Educational Codeforces Round 91 (Rated for Div. 2)

待補c++

  1. E
  2. F
  3. G

1. 題目分析

  • A:思惟
  • B: 思惟
  • C: 貪心
  • D: 思惟+分類討論

2. 題解

A. Three Indices

題意: 給定t個樣例,每一個樣例給定一個n,然後給出n個數字,要求判斷是否存在3個數字ai,aj,ak,知足i < j < k, 且aj > ai, aj > ak。若是存在輸出YES,然後輸出i, j, k;不存在輸出NO。T ~ 200, n ~ 1000
題解: 先正着掃一遍,判斷當前數字前最小的那個數字下標;再倒着掃一遍,判斷當前數字後最大的數字的下標。然後正着掃一遍判斷當前數字前是否有比它小的數字,當前數字後是否有比它大的數字便可。O(n)
代碼:

測試

#include <bits/stdc++.h>
 
using namespace std;
 
int const N = 1e3 + 10;
int a[N], n, T, le[N], ri[N];
 
int main() {
    cin >> T;
    while (T--) {
        memset(ri, -1, sizeof ri);
        memset(le, -1, sizeof le);
        cin >> n;
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        int minv1 = 1e9 + 10, minv2 = 1e9 + 10, minid1 = -1, minid2 = -1;
        for (int i = 1; i <= n; ++i) {
            if (minv1 < a[i]) le[i] = minid1;
            if (a[i] < minv1) {
                minv1 = a[i];
                minid1 = i;
            }
        }
        for (int  i = n; i >= 1; --i) {
            if (minv2 < a[i]) ri[i] = minid2;
            if (a[i] < minv2) {
                minv2 = a[i];
                minid2 = i;
            }
        }
        
        int flg = 0;
        for (int i = 2; i <= n; ++i) {
            if (le[i] != -1 && ri[i] != -1) {
                cout << "YES\n";
                cout << le[i] << " " << i << " " << ri[i] << endl;
                flg = 1;
                break;
            }
        }
        if (flg == 1) continue;
        cout << "NO\n";
    }
    return 0;
}

B. Universal Solution

題意: 如今要和機器人玩猜拳,機器人的出拳方式已經知道了。人的出拳方式須要肯定,同時從何時出拳也須要肯定,請找到一種出拳方式,使得人不管是在何時出拳,勝利的機率都能最大。給出t個測試樣例,每一個測試樣例給出一個長度爲n的字符串,表示機器人的出拳方式。t ~ 1000, n ~ 2e5
代碼
題解: 不管是從何時出拳都要保證勝率最大,所以只須要統計當前機器人出拳的最多的那個是什麼便可,然後每次都成勝最多的那個便可。
代碼:


spa

#include <bits/stdc++.h>
 
using namespace std;
 
int T;
 
int main() {
    int R = 0, S = 0, P = 0;
    cin >> T;
    string s;
    while (T--) {
        cin >> s;
        R = 0, S = 0, P = 0;
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] == 'R' ) R++;
            else if (s[i] == 'S') S++;
            else if (s[i] == 'P') P++;
        }
        int maxv = max(R, max(S, P));
        if (R == maxv) {
            for (int i = 0; i < s.size(); ++i) 
                cout << 'P';
        }
        else if (S == maxv) {
            for (int i = 0; i < s.size(); ++i) 
                cout << 'R';
        }
        else if (P == maxv) {
            for (int i = 0; i < s.size(); ++i) 
                cout << 'S';
        } 
        cout << endl;
    }
    return 0;
}

C. Make It Good

題意: 如今有n個同窗,但願把這n個同窗分紅不少的非空的團隊,每一個團隊的能力值=團隊中能力值最低的同窗的能力值*團隊的人數,問最多可以組成多少個這樣的團隊。給定t個測試樣例,每一個測試樣例給出n和k,n表示有n個同窗,k表示團隊的最小能力值。然後給出n個數字表示每一個同窗的能力值。
題解: 考慮貪心處理,先把同窗按照能力值按照從小到大排序。然後從大到小掃描,若是當前同窗的能力值大於k,則能夠單獨組成團隊;若是小於k,那麼考慮增長團隊的人數;O(n)掃描便可
代碼:

code

#include <bits/stdc++.h>
 
using namespace std;
 
int const N = 2e5 + 10;
int T, a[N], n, x;
 
int main() {
    cin >> T;
    while (T--) {
        cin >> n >> x;
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        sort(a + 1, a + 1 + n);
        int res = 0, mul = 1e9, cnt = 0;
        for (int i = n; i >= 1; --i) {
            if (a[i] >= x) {
                res ++;
                // cout << "i:" << i << endl;
                continue;
            }
            else {
               mul = a[i];
               cnt++;
               if (mul * cnt >= x) {
                   res ++;
                //   cout << "i:" << i << endl;
                   cnt = 0;
               }
            }
            
        }
        cout << res << endl;
    }
    return 0;
}

D. Berserk And Fireball

題意: 如今有兩排戰士,第一排戰士有n個,對第一排戰士進行消滅必定數目後將會變成第二排戰士。消滅戰士的方式有兩種,第一種是選擇連續k個戰士,將其消滅,這將消耗x元;第二種是選擇兩個相鄰的戰士,消滅其中較小的那個戰士,這將消耗y元。第一行給定n和k,第二行給定x、k和y,第三行給出第一排戰士的編號,第四行給出第二排戰士的標號。大於最小的花費,若是不存在輸出-1.
題解: 題目給出了第二排戰士,全部只須要按照第二排戰士的的最後結果去匹配第一行戰士,就能夠獲得不少的分段,而後計算是否能夠刪除這些分段,若是可以刪除,求出最小的花費便可,須要分類討論。
若是序列 b 中元素的出現順序與 a 不一致,則無解。
不然根據 b 將 a 分割爲一個個區間,對每個區間進行單獨操做。
對於一個長度小於 k 的區間:



排序

  • 若是區間最大值大於兩端的分割點,則無解
  • 不然花費爲 size×y
    對於一個長度大於等於 k 的區間:
  1. 若是區間最大值大於兩端的分割點,則必須使用一次操做一
    • 若是操做一花費較小,花費爲 ⌊sizek⌋×x+size % k×y
    • 若是操做二花費較小,花費爲 x+(size−k)×y
  2. 若是區間最大值小於兩端的分割點,則可沒必要使用操做一
    • 若是操做一花費較小,花費爲 ⌊sizek⌋×x+size % k×y
    • 若是操做二花費較小,花費爲 size×y

代碼:ip

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
int main() {
    ll n, m, x, k, y; cin >> n >> m >> x >> k >> y;
    int a[n] = {};
    int pos[n] = {};
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        --a[i];
        pos[a[i]] = i;
    }
    int b[m] = {};
    int mx_pos = 0;
    bool skip[n] = {}; //記錄在 a 中的分割點
    for (int i = 0; i < m; i++) {
        cin >> b[i];
        --b[i];
        if (pos[b[i]] < mx_pos) {
            cout << -1 << "\n";
            return 0;
        } else mx_pos = pos[b[i]];
        skip[b[i]] = true;
    }
    vector<vector<int>> v; //存儲每一個區間
    vector<pair<int, int>> border; //存儲每一個區間兩端的分割點
    vector<int> t; //每一個區間
    int l = -1, r = -1; //左右端點
    for (int i = 0; i < n; i++) {
        if (skip[a[i]]) { //若是遇到區間分割點
            if (l == -1 and r == -1) { //第一個區間只有右端點
                r = a[i];
            } else { //以後區間的左端點爲上一個區間的右端點
                l = r;
                r = a[i];
            }
            if (t.size() > 0) {
                v.push_back(t);
                border.emplace_back(l, r);
                t.clear();
            }
            continue;
        }
        t.push_back(a[i]);
    }
    if (t.size() > 0) {
        l = r;
        v.push_back(t);
        border.emplace_back(l, -1);
        t.clear();
    }
    ll ans = 0;
    for (int i = 0; i < v.size(); i++) {
        bool seg_mx = *max_element(v[i].begin(), v[i].end()) > max(border[i].first, border[i].second);
        if (v[i].size() < k) {
            if (seg_mx) {
                cout << -1 << "\n";
                return 0;
            }
            ans += v[i].size() * y;    
        } else {
            if (seg_mx) 
                ans += min(x + (v[i].size() - k) * y, v[i].size() / k * x + v[i].size() % k * y);
            else
                ans += min(v[i].size() * y, v[i].size() / k * x + v[i].size() % k * y);
        }
    }
    cout << ans << "\n";
}
相關文章
相關標籤/搜索