Codeforces Round #638 (Div. 2)

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

A - Phoenix and Balance

题意

将长为偶数的等比数列 $2^1, 2^2, 2^3, ... , 2^n$ 分为两个长为 $\frac{n}{2}$,相差最小的子序列。

题解

原序列可以看做一个二进制数,比如当 $n = 6$ 时:

原序列可以看做:$111111$

相差最小的分法即为:

$100011$

$011100$

代码

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

void solve() {
    int n; cin >> n;
    int a = 0, b = 0;
    a += 1 << n;
    for (int i = 1; i < n / 2; i++) {
        a += 1 << i;
    }
    for (int i = n / 2; i < n; i++) {
        b += 1 << i;
    }
    cout << a - b << "\n";
}

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

B - Phoenix and Beauty

题意

向一个长为 $n$ 的数组中插入一些数,使得每个长为 $k$ 的连续子数组的和为定值。

题解

利用原数组中的值构造构造一个大小为 $k$ 的循环数组,将原数组中的每个数都用该循环数组代替。

代码

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

void solve() {
    int n, k; cin >> n >> k;
    set<int> st;
    for (int i = 0; i < n; i++) {
        int x; cin >> x;
        st.insert(x);
    }
    if (st.size() > k) {
        cout << "-1" << "\n";
        return;
    }
    if (st.size() < k) {
        for (int i = 1; i <= n; i++) {
            st.insert(i);
            if (st.size() == k) break;
        }
    }
    cout << n * k << "\n";
    for (int i = 0; i < n; i++) {
        for (int j : st) cout << j << ' ';
    }
    cout << "\n";
}

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

C - Phoenix and Distribution

题意

将字符串 $s$ 分为 $k$ 个非空串,找出使得 $k$ 个非空串中字典序最大的字符串字典序最小的方案。

题解

先给每个字符串分配一个字母保证非空,此时如果只剩下一种字母,给字典序最小的一些字符串循环分配即可。

如果剩下的字母多于一种,则全部分给一个字符串,因为这样分较大的字母最靠后,字典序最小。

代码

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

void solve() {
    int n, k; cin >> n >> k;
    string str; cin >> str;
    int cnt[26] = {};
    for (char c : str) cnt[c - 'a']++;
    string s[k];
    vector<char> init_s;
    int len = -1;
    for (int i = 0; i < 26; i++) {
        if (cnt[i] > 0) {
            if (len == -1) len = min(k, cnt[i]);
            int need = k - init_s.size();
            int mi = min(need, cnt[i]);
            for (int j = 0; j < mi; j++) {
                init_s.push_back(char('a' + i));
            }
            cnt[i] -= mi;
        }
    }
    for (int i = 0; i < k; i++) {
        s[i] += init_s[i];
    }
    int type = 0;
    for (int i = 0; i < 26; i++) {
        type += cnt[i] > 0;
    }
    for (int i = 0; i < 26; i++) {
        if (cnt[i] > 0) {
            for (int j = 0; j < cnt[i]; j++) {
                if (type == 1) s[j % len] += char('a' + i);
                else s[0] += char('a' + i);
            }
        }
    }
    sort(s, s + k);
    cout << s[k - 1] << "\n";
}

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

D - Phoenix and Science

题意

开始时有 $1$ 个质量为 $1$ 的细菌,白天可以选择部分细菌分裂,晚上每个细菌的质量增加 $1$,问最少需要多少天总质量能达到 $m$,输出分裂方案。

题解

  • 细菌分裂只影响之后每晚增加的质量

考虑质量增长最快的方式——指数增长:每个白天所有的细菌都分裂,这样每晚增加的质量即为一个 $a_0 = 1,\ q = 2$ 的等比数列,求出和小于等于 $m$ 的最长等比数列,将多出来的质量分进其中的某一天即可,相邻两晚的质量之差即为白天多分裂的个数。

代码

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

void solve() {
    int n; cin >> n;
    vector<int> m;
    for (int i = 1; i <= n; i *= 2) {
        m.push_back(i);
        n -= i;
    }
    if (n > 0) {
        m.push_back(n);
        sort(m.begin(), m.end());
    }
    cout << m.size() - 1 << "\n";
    for (int i = 1; i < m.size(); i++) 
        cout << m[i] - m[i - 1] << " \n"[i == m.size() - 1];
}

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

 

posted @ 2020-05-02 02:00  Kanoon  阅读(348)  评论(0编辑  收藏  举报