Codeforces Round #638 (Div. 2) A~C题解

A

题意:

给出 2 1 , 2 2 , 2 3 , 2 4 , . . . 2 n 2^1,2^2,2^3,2^4,...2^n 这n个数,n是偶数,将这n个数分成相等的两部分,问如何分配使这两部分的和之差最小,求出这个最小值。

题解:

我们知道 2 1 + 2 2 + 2 3 + . . . + 2 n 1 < 2 n 2^1 + 2^2 + 2^3 + ... +2^{n- 1} < 2^n ,所以分配到 2 n 2^n 的一部分一定是两堆数中较大的一堆,我们要使这一堆数之和最小来缩短两堆的差距。所以将前 n / 2 1 n / 2 - 1 个数分配给这堆即可。

B

题意:

在这里插入图片描述
一个数组是漂亮的,当且仅当它的任意一个长度为 k k 的子区间的和都为一个相同值的时候。给出我们一个数组,问是否能够向数组中插入若干个数字,使这个数组变成漂亮的。如果能输出最后的数组。无需最小化插入数字的数目。

题解:

我们不难发现,如果一个数组如果所有长度为k的子区间都为一个相同值的时候,那么这个数组就是以k为周期循环的。比如k = 4,数组为1 2 3 4 1 2 3 4 1 2 3。
因为这样从一个子区间走向下一个子区间的时候 s u m a [ l ] + a [ l + k ] sum - a[l] + a[l + k] 才能等于 s u m sum
也就是说这个数组最多只能有 k k 个不同的数字。
我们通过统计给出的数组中的不同的数字,如果大于 k k ,那么肯定是不可以的。
如果小于等于 k k ,我们就把不同的数字都加入循环节,如果循环节长度不等于 k k ,可以随便补充数字。我们将循环节重复 n n 次,那么原数列的中每一个元素都对应一个循环节,也就是能通过插入数字的方式得到这个循环节。
能算出最后长度最长100 * 100小于等于10000。

代码:

/**
 1. Author : Xiuchen
 2. Date : 2020-05-01-23.59.04
 3. Description : B.cpp
*/
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<math.h>
#include<iostream>
#include<algorithm>
//#define DEBUG
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 110;
int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}
int t;
int n, k, num[maxn], a[maxn];
vector<int> v;
int main(){
#ifdef DEBUG
    freopen("input.txt", "r", stdin);
//  freopen("output.txt", "w", stdout);
#endif
    cin >> t;
    while(t--){
        cin >> n >> k;
        v.clear();
        memset(num, 0, sizeof(num));
        for(int i = 1; i <= n; i++){
            cin >> a[i];
            if(num[a[i]] == 0) v.push_back(a[i]);
            num[a[i]]++;
        }
        if(v.size() > k) cout << -1 << endl;
        else{
            cout << k * n << endl;
            for(int i = 1; i <= n; i++){
                for(int j = 0; j < v.size(); j++) cout << v[j] << " ";
                for(int j = 1; j <= k - v.size(); j++) cout << 1 << " ";
            }
            cout << endl;
        }
    }
    return 0;
}

C.

题意:

在这里插入图片描述
给出一个字符串,分成 k k 个非空的字符串,问如何分配使这 k k 个字符串中的字典序最大的一个字符串字典序最小。给出字符串相当于给出了字符及其个数,分配的时候顺序可以打乱。详细见题目样例。

题解:

既然顺序是可以随便动的,只要个数不变就行。那么我们不妨将所有字符排个序。
首先这k个字符串的第一个字母都要尽量的小。所以把原字符串的排完序后的前k个字符依次分配给他们。

  1. s [ 1 ] ! = s [ k ] s[1] != s[k] ,也就是说首个字母最后一个串分配的比第一个串分配的大。
    这个时候我们可以直接就把后面所有的字符都分给第一个字符串,这不会改变最后一个字符串是最大字符串的事实,又保证了最后一个字符串尽可能地小。如第五个样例。
  2. s [ 1 ] = s [ k ] s[1] = s[k]
    这个时候就不能妄下定论了。如果像上面一样做的话,第一个串就变成了最大串,这个最大串就不能保证尽可能小了。如第一组样例。
    这个时候我们依然可以分两种情况。
    第一种:后面所有的字符都相同。那最大的字符串一定是分配到个数最多的那个。我们将剩下的字符平均分到每个字符串就可以保证最大值最小化了。
    第二种:后面的字符不相同。如样例2。我们假设第一个字符串是最大的。如果我们把后面的一些字符分配到第二个往后的字符串上。
    要么会让第一个字符串不是最大的串,使后面的最大串大于原本把所有字符分配给第一个串的值。
    要么就是第一个字符串依然是最大的串,但这个串的值依然是大于把所有字符分配给第一个串的值。
    例如: 样例二,或者6 2 aabcde。大家手推一下就能发现。这种情况把所有剩余字符分配给第一个字符串是最优的。

这样的话所有的情况都覆盖。详细见代码。

/**
* Author : Xiuchen
* Date : 2020-05-02-00.26.19
* Description : C.cpp
*/
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<math.h>
#include<iostream>
#include<algorithm>
//#define DEBUG
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 1e5 + 100;
int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}
int t;
int k, n;
char s[maxn];
vector<char> v;
int main(){
#ifdef DEBUG
    freopen("input.txt", "r", stdin);
//  freopen("output.txt", "w", stdout);
#endif
    cin >> t;
    while(t--){
        v.clear();
        cin >> n >> k;
        scanf("%s", s + 1);
        sort(s + 1, s + n + 1);
        if(s[1] != s[k]) cout << s[k] << endl;
        else{
            v.push_back(s[1]);
            if(n > k){
                if(s[k + 1] != s[n]){
                    for(int i = k + 1; i <= n; i++)
                        v.push_back(s[i]);
                }
                else{
                    int num = ceil(1.0 * (n - k) / k);
                    for(int i = 1; i <= num; i++)
                        v.push_back(s[k + 1]);
                }
            }
            for(int i = 0; i < v.size(); i++) cout << v[i];
                cout << endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44607936/article/details/105897472