Codeforces Round #656 Div3 前四题(也许会更新

目录

  • A - Three Pairwise Maximums
  • B - Restore the Permutation by Merger
  • C - Make It Good
  • D - a-Good String

A - Three Pairwise Maximums

啊啊啊啊啊该死的校园网自己断开了于是我写了老半天的题解一个字都没保存 再放送

思路:

  • 分四种情况讨论
    1. 三个数都不相等
    2. 两个数相等,另一个数比这两个大
    3. 两个数相等,另一个数比这两个小
    4. 三个数都相等

情况1、2无解,如图
Codeforces Round #656 Div3 前四题(也许会更新_第1张图片同样的推导方法用于3、4,
可得情况3取a = b = c = x = y = z,情况4取a > b && a > c时满足题目要求。由于可以按照任意顺序输出答案,所以直接输出就行,不用考虑abc哪个大哪个小(不愧是A题)

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1005
typedef long long ll;
using namespace std;
///x > y > z, if(x == max(a, b) == b)  z = max(b, c) = b   if(x == max(a, b) == a) y = max(a, c) = a    无解
///x = y > z   x == max(a, b) == a y == max(a, c) == a z == max(b, c) == b||c  a > b||c
///x = y < z   x == max(a, b) == a y == max(a, c) == a z == max(b, c) == c     a > b||c    无解
///x = y = z   x == y == z == a == b == c

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        ll x, y, z;
        ll s[3] = {0};
        scanf("%lld%lld%lld", &x, &y, &z);
        if(x != y && y != z && z != x)///   x > y > z
        {
            printf("NO\n");
            continue;
        }
        if(x == y && y == z)/// x = y = z
        {
            printf("YES\n");
            printf("%lld %lld %lld\n", x, y, z);
            continue;
        }
        s[0] = x;
        s[1] = y;
        s[2] = z;
        sort(s, s + 3);
        if(s[0] == s[1])    ///x = y < z
        {
            printf("NO\n");
            continue;
        }
        printf("YES\n");
        printf("%lld %lld %lld\n", s[2], s[0], s[0]);
    }
}

B - Restore the Permutation by Merger

思路: 设一个空的答案数组,遍历原数组,遇到答案数组中没有的数字就加入答案数组,遇到已经有的数字则跳过

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1005
typedef long long ll;
using namespace std;

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        int cnt = 0;
        int a[N] = {0};
        int per[N] = {0};//就是vis数组,1表示已存在于答案数组中,0表示无
        int ans[N] = {0};
        scanf("%d", &n);
        for(int i = 1; i <= 2 * n; i++)
        {
            scanf("%d", &a[i]);
        }
        for(int i = 1; i <= 2 * n; i++)
        {
            if(per[a[i]])//答案数组已经有该数字
                continue;
            per[a[i]] = 1;
            ans[cnt++] = a[i];
        }
        for(int i = 0; i < cnt - 1; i++)
            printf("%d ", ans[i]);
        printf("%d\n", ans[cnt - 1]);
    }
    return 0;
}

C - Make It Good

思路:
只有当剩余数组有且仅有一个极大值(在0-m单调递增,m-n单调递减),或者完全单调(递增或者递减),才满足题意。
又由题目要求的是删除前缀,所以我们从后向前遍历:

  1. 先判断数组是否(由后向前)单调递增
  2. 在遇到第一个递减的数组元素后,开始判断数组接下来是否单调递减
  3. 在又遇到一个单调递增的数组元素后,记录此时的下标,输出即可

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1000100
typedef long long ll;
using namespace std;

int a[N];
int n;

void init()
{
    memset(a, 0, sizeof(a));
}

void solve()
{
    int flag = 0;
    int index = n;
    for(int i = n - 1; i > 0; i--)
    {
        if(flag == 0)
        {
            if(a[i - 1] < a[i])
            {
                flag = 1;
            }
            continue;
        }
        if(a[i - 1] > a[i])
        {
            index = i;
            break;
        }
    }
    if(index == n)
        index = 0;
    printf("%d\n", index);
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
        }
        solve();
    }
}

D - a-Good String

思路:分治法

我最开始的思路是:

  1. 数出左右串中a较多的那个串,将它全部替换成a,并将需要的步数加入答案;
  2. 数出另一个串左右串中b较多的那个串,将它全部替换成b,并将需要的步数加入答案

WA了好几遍,最后发现在这组数据的时候,出错了
在这里插入图片描述
abcdefgh改成bbcdaaaa只需要5步,但是按照我的算法是7步。
于是老老实实全部分治,就AC了

修改后的思路:

  1. (左串全部变a)步数 = 字符串长度 / 2 - 左串中a的个数 + 右串变为b-good需要更改的字符数量;
  2. (右串全部变a)步数 = 字符串长度 / 2 - 右串中a的个数 + 左串变为b-good需要更改的字符数量;
  3. 最小步数 = min(1, 2)
  4. 依次递归

代码:


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1000100
typedef long long ll;
using namespace std;

char str[N];
int n;
int ans;

void init()
{
    for(int i = 0; i + 'a' <= 'z'; i++)
    {
        str[i] = 'a' + i;
    }
    ans = 0;
}

int solve(int len, int index, int arr[])///str[index]表示轮到哪个字母
{
    int res = 0;
    if(len == 1)
    {
        return arr[0] != index;
    }
    int *ll = new int[len / 2];
    int *rr = new int[len / 2];
    int num1 = 0, num2 = 0;
    for(int i = 0; i < len / 2; i++)
    {
        ll[i] = arr[i];
        if(ll[i] == index)
            num1++;
    }
    for(int i = 0, j = len / 2; i < len / 2; i++, j++)
    {
        rr[i] = arr[j];
        if(rr[i] == index)
            num2++;
    }
    res = min(len / 2 - num1 + solve(len / 2, index + 1, rr), len / 2 - num2 + solve(len / 2, index + 1, ll));
    delete []ll;
    delete []rr;
    return res;
}

int main()
{
    int T;
    scanf("%d", &T);
    init();
    while(T--)
    {
        scanf("%d", &n);
        if(n == 1)
        {
            getchar();
            char c = getchar();
            printf("%d\n", c != 'a');
            continue;
        }
        getchar();
        int *l = new int[n / 2];
        int *r = new int[n / 2];
        int num1 = 0, num2 = 0;
        for(int i = 0; i < n / 2; i++)
        {
            char c = getchar();
            l[i] = c - 'a';
            if(l[i] == 0)
                num1++;
        }
        for(int i = 0; i < n / 2; i++)
        {
            char c = getchar();
            r[i] = c - 'a';
            if(r[i] == 0)
                num2++;
        }
        ans = min(n / 2 - num1 + solve(n / 2, 1, r), n / 2 - num2 + solve(n / 2, 1, l));
        printf("%d\n", ans);
        delete []l;
        delete []r;
    }
    return 0;
}

一点小小的总结:

  • 这场是赛后重现,白天做题状态比晚上好太多了qwq但是依然没能在时限内将D题做对。
  • 最大的问题就是思路都有,实现的一塌糊涂(比如D题分治)。做题太少的缘故
  • 还有对数据大小的估计也是,没有估计好C题的数据量,白白RE两发

第一次写博客,发现自己懂和能讲清楚还差了好远,经常写着写着不知道怎么表达了。多多包涵,努力进步。

你可能感兴趣的:(CF补题总结)