Codeforces Round 1050 (Div. 4)

76 阅读4分钟

codeforces.com/contest/214…

A. Sublime Sequence (800)

题目大意:数字 x,-x,x,-x,... 求和

解决思路:循环累加即可

#include <iostream>
using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int x, n;
        cin >> x >> n;
        int sum = 0;
        while (n--) {
            sum += x;
            x = -x;
        }
        cout << sum << endl;
    }

    return 0;
}

B. Lasers (800)

题目大意:从(0, 0)走向(x, y), 其中有 n 条横向和 m 条纵向的激光,问至少要穿过多少个激光线。

解题思路:横向 + 纵向的数量之和

#include <iostream>
using namespace std;

int main() {
    int t;
    cin >> t;

    while (t--) {
        int n, m, x, y;
        cin >> n >> m >> x >> y;

        int a, b;
        for (int i = 0; i < n; i++) {
            cin >> a;
        }

        for (int i = 0; i < m; i++) {
            cin >> b;
        }

        cout << n + m << endl;
    }

    return 0;
}

C. Pacer (900)

题目大意:从地点 0 和 1 来回移动,且移动 1 次得 1 分;第 0 分钟在位置 0,规定了第几分钟要在哪个位置,问经过 n 分钟,最多能得多少分。

解题思路:可以把 n 分钟分成多干段,每一段求最大得分,加起来就是最大得分。

#include <iostream>
using namespace std;

int main() {

    int t;
    cin >> t;

    int MAX_N = 200000 + 10;

    int a[MAX_N], b[MAX_N];

    while (t--) {
        int n, m;
        cin >> n >> m;

        for (int i = 1; i <= n; i++) {
            cin >> a[i] >> b[i];
        }

        a[0] = 0;
        b[0] = 0;

        int sum = 0;

        for (int i = 1; i <= n; i++) {
            int d = a[i] - a[i - 1];
            if (b[i] == b[i - 1]) {
                if (d % 2 == 1) {
                    sum += d - 1;
                } else {
                    sum += d;
                }
            } else {
                if (d % 2 == 1) {
                    sum += d;
                } else {
                    sum += d - 1;
                    ;
                }
            }
        }

        cout << sum + m - a[n] << endl;
    }

    return 0;
}

D. Destruction of the Dandelion Fields (1000)

题目大意:有 n 个整数,有一个收割机,一开始是关闭状态,如果遇到奇数状态会转换(开启和关闭相互转换),遇到偶数则不会;问收割机经过所有得数字,问收割之和最大多少,经过得顺序随意。

解题思路:

1、如果都是偶数,则为 0,因为没有开启的机会。

2、如果存在奇数,则偶数一定都可以做贡献。所以只需要考虑所有的奇数按照什么样的顺序收购即可:按照一大一小收割。

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int t;
    cin >> t;

    while (t--) {
        int n;
        cin >> n;

        vector<int> b;

        long long sum = 0;
        for (int i = 0; i < n; i++) {
            int a;
            cin >> a;

            if (a % 2 == 0) {
                sum += a;
            } else {
                b.push_back(a);
            }
        }

        if (b.size() == 0) {
            cout << 0 << endl;
        } else {
            int m = b.size();
            sort(b.begin(), b.end());

            for (int i = m - 1; i >= m / 2; i--) {
                sum += b[i];
            }
            cout << sum << endl;
        }
    }

    return 0;
}

E. Split (1200)

题目大意:有一个数组,问有多少个子数字是好的。

解决思路:

1、 不可能枚举所有的子数组,2*n 次幂,复杂度太大。

2、 可以采用滑动窗口,累计计算满足条件的个数。

#include <iostream>
#include <vector>
using namespace std;

int main() {

    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;

        int a[n + 10];
        vector<int> cnt(n + 10, 0);

        for (int i = 0; i < n; i++) {
            cin >> a[i];
            cnt[a[i]]++;
        }

        long long res = -1;

        for (int i = 1; i <= n; i++) {
            if (cnt[i] % k != 0) {
                res = 0;
                break;
            } else {
                cnt[i] /= k;
            }
        }

        if (res == 0) {
            cout << res << endl;
            continue;
        }

        res = 0;

        // 滑动窗口
        int left = 0;
        vector<int> window(n + 10, 0);

        for (int right = 0; right < n; right++) {
            window[a[right]]++;

            while (window[a[right]] > cnt[a[right]]) {
                window[a[left]]--;
                left++;
            }

            res += right - left + 1;
        }

        cout << res << endl;
    }

    return 0;
}

F. Gravity Falls (1800)

题目大意:有 n 个数组,可以按照任意顺序从低到高水平排序,由于重力的作用,上面数字的元素会往下掉,问第一层的序列字典序最小是多少。

解题思路:

1、先按照第 0 个元素从小到大排序,则第一个数组元素字典序肯定最小,全部加到答案中,假设有 m 个。

2、然后纵向将所有的数字前 m 个元素去掉,又形成了新的数组序列。

然后按照(1)(2)反复操作,最终得到答案。

一开始以为只排序第一次就行

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
 
int main() {
 
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
 
        vector<vector<int>> a(n);
 
        int max_k = 0;
 
        for (int i = 0; i < n; i++) {
            int k;
            cin >> k;
            for (int j = 0; j < k; j++) {
                int b;
                cin >> b;
                a[i].push_back(b);
            }
            max_k = max(max_k, k);
        }
 
        vector<int> res;
 
        while (res.size() < max_k) {
            // cout << "aaa: " << a.size() << endl;
 
            // for (int i = 0; i < a.size(); i++) {
            //     for (int j = 0; j < a[i].size(); j++) {
            //         cout << a[i][j] << ' ';
            //     }
            //     cout << endl;
            // }
 
            sort(a.begin(), a.end());
 
            for (size_t i = 0; i < a[0].size(); i++) {
                res.push_back(a[0][i]);
            }
 
            size_t begin = a[0].size();
 
            vector<vector<int>> a_copy;
            for (int i = 0; i < a.size(); i++) {
                vector<int> tmp;
 
                for (int j = begin; j < a[i].size(); j++) {
 
                    tmp.push_back(a[i][j]);
                }
                if (!tmp.empty()) {
                    a_copy.push_back(tmp);
                }
            }
            a = a_copy;
        }
 
        for (size_t i = 0; i < res.size(); i++) {
            cout << res[i] << " ";
        }
        cout << endl;
    }
 
    return 0;
}

G. Farmer John's Last Wish (1900)

看起来有点难