Codeforces Round #715 (Div. 2)

Codeforces Round #715 (Div. 2)

A Average Height

题目

给定\(n\)个数,将他们重新排列,使得若一对相邻数的平均数为整数,则称它们上镜,求上镜数最大值对应的重排方案.

思路

显然,奇数放一堆,偶数放一堆.

代码

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

int n;
vector <int> a[2];
void solve() {
    a[0].clear() , a[1].clear();
    n = read();
    for(int i = 1 ; i <= n ; i++) {
        int tmp = read();
        a[tmp & 1].push_back(tmp);
    }
    for(int i : a[1])a[0].push_back(i);
    for(int i : a[0])printf("%d " , i);
    putchar('\n');
}
int main() {
    int T = read();
    while(T--)solve();
    return 0;
}

B TMT Document

题目

给定一个由T,M构成的字符串,将它划分为若干个不相交的子序列,使得所有子序列都等于TMT,问有没有解.

思路

猜到的一个结论.

T的数量不是M的数量,答案为NO.

若从前往后扫一遍,某时刻M的数量大于T的数量,答案为NO.

若从前往后扫一遍,某时刻M的数量大于T的数量,答案为NO.

若以上三个均不满足,答案为YES.

证明:?

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

const int N = 1e5 + 10;
int n;
int s[N];
bool flag[N];
stack <int> stk;
void solve() {
    n = read();

    for(int i = 1 ; i <= n ; i++)s[i] = readc<'A' , 'Z'>();
    int m = 0 , t = 0;
    for(int i = 1 ; i <= n ; i++)m += (s[i] == 'M') , t += (s[i] == 'T');
    if(m * 2 != t) {
        puts("NO");
        return ;
    }
    m = 0 , t = 0;
    for(int i = 1 ; i <= n ; i++) {
        m += (s[i] == 'M') , t += (s[i] == 'T');
        if(m > t) {
            puts("NO");
            return ;
        }
    }
    m = 0 , t = 0;
    for(int i = n ; i > 0 ; i--) {
        m += (s[i] == 'M') , t += (s[i] == 'T');
        if(m > t) {
            puts("NO");
            return ;
        }
    }
    puts("YES");
    return ;
}
int main() {
    int T = read();
    while(T--)solve();
    return 0;
}

C The Sports Festival

题目

给定长度为 \(n\) 的序列 \(s\),你可以改变序列 \(s\) 的顺序,求

\[\sum_{i=1}^n(\max_{j=1}^is_j-\min_{j=1}^is_j) \]

的最小值。

\(1\leq n\leq2\times10^3;1\leq s_i\leq10^9;\)

思路

我们先对\(s\)进行排序.

一个想法是如果已经将\(s_{l\sim r}\)放入重排数组,那么重排数组的下一个数是\(s_{l-1}\)\(s_{r+1}\),自己证.

一开始还在想枚举第一个数,贪心生成重排数组,然后发现根本找不到一个正确的贪心策略.

然后通过某种途径这题可以用DP处理.

\(f_{i,j}\)表示我们已经将\(s_{i\sim j}\)放入重排数组中的最小的那啥那啥(上面的数学公式),

根据上面的结论,我们容易得到转移:

if(i == j)f[i][j] = 0;
else f[i][j] = min(
	f[i + 1][j] + a[j] - a[i],
	f[i][j - 1] + a[j] - a[i]
) ;

注意我们已经排序了,所以最小最大值分别是\(s_i,s_j\)(对应代码中的\(a_i,a_j\))

我真菜

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>

#define int long long
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

const int N = 2010;
int n;
int a[N];
int sum[N];

int f[N][N];
void solve() {
    n = read();
    for(int i = 1 ; i <= n ; i++)
        a[i] = read();
    sort(a + 1 , a + n + 1);
    for(int i = n ; i > 0 ; i--)
        for(int j = i ; j <= n ; j++) {
            if(i == j)f[i][j] = 0;
            else f[i][j] = min(
                f[i + 1][j] + a[j] - a[i],
                f[i][j - 1] + a[j] - a[i]
            ) ;
        }
    cout << f[1][n];
}
signed main() {
    solve();
    return 0;
}

D Binary Literature

题目

给你一个正整数 \(n\) 和三个长度为 \(2\times n\) 的 01 字符串 \(s_1,s_2,s_3\)。你需要构造一个 01 字符串 \(S\),使得:

  • 字符串 \(S\) 的长度不能超过 \(3\times n\)
  • \(s_1,s_2,s_3\) 当中至少有两个字符串是 \(S\) 的子序列。

可以证明一定有解,有多种解时输出任意一种即可。\(T\) 组数据。

\(1\leq T\leq10^4;1\leq n,\sum n\leq10^5;\)

思路

我们仔细想想为什么一定有解,如果能证出来这题也就基本切了.

想几个问题:

  1. 为什么是三个01串而不是两个.
  2. 为什么\(s\)的长度为\(2n\),\(S\)的长度为\(3n\).

第一个问题的反例很容易找到,如果他给一个全是0的串和一个全是1的串,至少要\(4n\)的长度才能构造出\(S\).

但是一但我们有了第三个字符串,就不一样了.

如果第三个字符串0的个数多,我们就可以补0使得全是0的字符串成为子序列,1的个数多同理.

最坏情况下,补完后长度是\(3n\).

然后,我们顺理成章地想到在三个字符串中选出两个,暂时重命名为\(a,b\)串,使得两个串中0的同时数量大于等于\(n\)1的数量同时大于等于\(n\).(显然,一定可以选出来)

如果0的数量多,我们就往全是0的串里插1,使得\(a,b\)是子序列.

否则,就往1里面插0.

由于至少有\(n\)个字符是\(a,b\)共用的,所以长度不超过\(3n\).

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

const int N = 3e5;
int n;
char s[5][N];
int zero[5];
char ans[N * 2];
int fol[N];
void solve() {
	memset(zero , 0 , sizeof(zero));
    int rev = false;
    n = read();
    
    for(int i = 0 ; i <= n * 3 ; i++)
    	ans[i] = 0 , fol[i] = 0;
    	
    for(int i = 1 ; i <= 3 ; i++)
        for(int j = 1 ; j <= n * 2 ; j++)
            s[i][j] = readc<'0' , '1'>() , zero[i] += (s[i][j] == '0');
    char *p , *q;
    p = q = NULL;
    for(int i = 1 ; i <= 3 ; i++)
        if(zero[i] >= n) {
            if(p == NULL)p = s[i];
            else q = s[i];
        }
    if(q == NULL) {
    	p = q = NULL;
        for(int i = 1 ; i <= 3 ; i++)
            if(zero[i] <= n) {
                if(p == NULL)p = s[i];
                else q = s[i];
            }
        rev = true;
        for(int i = 1 ; i <= n * 2 ; i++)
            p[i] ^= 1 , q[i] ^= 1;
    }
    int z = 0;
    for(int i = 1 ; i <= n * 2 ; i++) {
        if(p[i] == '1')++fol[z];
        else ++z;
    }
    z = 0;
    for(int i = 1 ; i <= n * 2 ; i++) {
        if(q[i] == '1')++fol[z];
        else ++z;
    }
    int cnt = 0;
    while(fol[0])ans[++cnt] = '1' , --fol[0];
    for(int i = 1 ; i <= n * 2 ; i++) {
        ans[++cnt] = '0';
        while(fol[i])ans[++cnt] = '1' , --fol[i];
    }
    for(int i = 1 ; i <= n * 3 ; i++)
        if(ans[i] >= 48)putchar(rev ^ ans[i]);
        else break;
    putchar('\n');
}
int main() {
    int T = read();
    while(T--)solve();
    return 0;
}
posted @ 2021-11-12 07:27  追梦人1024  阅读(33)  评论(0编辑  收藏  举报