Educational Codeforces Round 75 (Rated for Div. 2)

比赛链接:https://codeforces.com/contest/1251

A - Broken Keyboard

题意

键盘的有些字母键是坏的,按一下会输入两个字母,正常的字母键一次只会输入一个字母,给出一段输入序列,判断哪些字母键是正常的。

题解

连续出现奇数次的字母一定是正常的。

代码

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

void solve() {
    string s; cin >> s;
    set<char> st;
    for (int i = 0; i < s.size(); ) {
        int j = i + 1;
        while (j < s.size() and s[j] == s[i]) 
            ++j;
        if ((j - i) % 2 == 1)
            st.insert(s[i]);
        i = j;
    }
    for (char c : st) cout << c;
    cout << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

B - Binary Palindromes

题意

$n$ 个 $01$ 串间不同位置的字符可以自由交换,计算最多可以形成多少个回文串。

题解

有一个很神奇的特性就是,如果有奇数长度的串,所有字符串都可以变为回文串。

如果没有的话,对于偶数串来说,如果 $0$ 和 $1$ 都出现奇数次是不可以组成回文串的,但是这种串可以两两结合交换为回文串,所以需要记录是否有奇数长的串,以及不回文的偶数长的串的个数。

代码

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

void solve() {
    int n; cin >> n;
    bool len_odd = false;
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        string s; cin >> s;
        if (s.size() % 2) 
            len_odd = true;
        else {
            int cnt_0 = count(s.begin(), s.end(), '0');
            int cnt_1 = count(s.begin(), s.end(), '1');
            if (cnt_0 % 2 and cnt_1 % 2) ++cnt;
        }
    }
    cout << ((len_odd or cnt % 2 == 0) ? n : n - 1) << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

C - Minimize The Integer

题意

有一个数字串,相邻字符如果奇偶性不同可以相互交换,问这个数字串最小的值为多少。

题解

对于单独的奇数和偶数来说,它们的相对位置是不变的,所以依次记录奇数和偶数,每次取较小值即可。

代码

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

void solve() {
    string s; cin >> s;
    vector<char> odd, even;
    for (char c : s)
        if ((c - '0') % 2 == 1) 
            odd.push_back(c);
        else 
            even.push_back(c);
    int i = 0, j = 0;
    while (true) {
        if (i == odd.size()) {
            while (j < even.size())
                cout << even[j++];
            break;
        }
        if (j == even.size()) {
            while (i < odd.size())
                cout << odd[i++];
            break;
        }
        cout << (odd[i] < even[j] ? odd[i++] : even[j++]);
    }
    cout << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

D - Salary Changing

题意

你有 $n$ 个员工,打算给他们一共发 $s$ 元的薪资,每个员工能接受的薪资范围在 $[l_i,r_i]$ 之间,计算所有薪资中的中位数的最大值。

题解

二分中位数 $mid$,

  • 如果一个员工的 $r_i<mid$,那么只需给他发 $l_i$
  • 如果一个员工的 $l_i≥mid$,那么也只需给他发 $l_i$
  • 其余员工一定满足 $l_i < mid ≤ r_i$, 给 $l_i$ 较大的几个发 $mid$,其余的仍发 $l_i$ 即可

需要注意后两个人数至少应为总人数的一半以上才能满足 $mid$ 为所有薪资中的中位数。

代码

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
const int INF = 1e9 + 100;
const int N = 2e5 + 100;

ll n, s;
pair<int, int> a[N];

bool ok(ll mid) {
    ll tot = s;
    vector<int> v;
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        if (a[i].second < mid)
            tot -= a[i].first;
        else if (a[i].first >= mid)
            tot -= a[i].first, ++cnt;
        else
            v.push_back(a[i].first);
    }
    int half = (n + 1) / 2;
    if (cnt + v.size() < half) return false;
    sort(v.rbegin(), v.rend());
    int need = max(0, half - cnt);
    tot -= need * mid + accumulate(v.begin() + need, v.end(), 0LL);
    return tot >= 0;
}

void solve() {
    cin >> n >> s;
    for (int i = 0; i < n; i++)
        cin >> a[i].first >> a[i].second;
    int l = 0, r = INF;
    int ans = 0;
    while (l <= r) {
        int mid = (l + r) / 2;
        if (ok(mid)) {
            ans = mid;
            l = mid + 1;
        } else 
            r = mid - 1;
    }
    cout << ans << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

参考了 ~Lanly~ 的博客 ~ 

posted @ 2020-05-21 23:00  Kanoon  阅读(151)  评论(0)    收藏  举报