ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #789 (Div. 2)

2022-05-12 00:34:11  阅读:228  来源: 互联网

标签:子段 int s2 s1 789 Codeforces Tokitsukaze ++ Div


题集链接

A. Tokitsukaze and All Zero Sequence

题意

Tokitsukaze 有一个长度为 n 的序列 a。 对于每个操作,她选择两个数字 ai 和 aj (i≠j; 1≤i,j≤n)。

如果 ai=aj,则将其中之一更改为 0,否则将它们都更改为 min(ai,aj)。

Tokitsukaze 想知道将序列中的所有数字变为 0 的最小操作次数。可以证明答案总是存在的。

思路

由题意可知

如果 a 中含有 0 只要把所以非零数和 0 进行比较就可以了,需要操作的次数为非 0 数的个数。

如果 a 中没有 0 但是有两个相同的数,操作数为 n

如果 a 中没有相同的数,操作数为 n+1

代码

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

void solve()
{
    int n;
    cin >> n;
    map<int, int> ma;
    for (int i = 1; i <= n; i++)
    {
        int a;
        cin >> a;
        ma[a]++;
    }
    if (ma[0] > 0)
    {
        cout << n - ma[0] << endl;
        return;
    }
    for (auto x : ma)
    {
        if (x.second >= 2)
        {
            cout << n << endl;
            return ;
        }
    }
    cout << n + 1 << endl;
}

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

 

B1. Tokitsukaze and Good 01-String (easy version)

题意

这是问题的简单版本。两个版本之间的唯一区别是,较难的版本额外要求最小数量的子段。

Tokitsukaze 有一个二进制字符串s长度n,仅由0和1组成,n是偶数。

现在Tokitsukaze s成最小数量的连续子段,并且对于每个子段,每个子段中的所有数都是相同的。之后,s如果所有子段的长度都是偶数,则认为是好的。

例如,如果ss为“ 11001111 ”,将分为“ 11 ”、“ 00 ”和“ 1111 ”。它们的长度是2,2,4分别是偶数,所以“ 11001111 ”是好的。

另一个例子,如果s为“ 1110011000 ”,将分为“ 111 ”、“ 00 ”、“ 11 ”和“ 000 ”,它们的长度分别为3,2,2,3. 显然,“ 1110011000 ”不好。

Tokitsukaze 想使s改变一些位置的值. 具体来说,她可以执行任意次数的操作:改变 si 为“ 0 ”或“ 1 ”(1≤i≤n)。

你能告诉她最少的修改次数吗?

思路

因为字段长度都为偶数,因此我们可以每次判断2位,这2位必须为相同的数。

我们只要记录有几个不同的就是要修改的次数。

代码

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

void solve()
{
    int n;
    string s;
    cin >> n >> s;
    int cnt = 0;
    for (int i = 0; i < n; i = i + 2)
    {
        if (s[i] != s[i + 1])
            cnt++;
    }
    cout << cnt << endl;
}

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

 

B2. Tokitsukaze and Good 01-String (hard version)

题意

这是问题的困难版本。两个版本之间的唯一区别是,较难的版本额外要求最小数量的子段。

Tokitsukaze 有一个二进制字符串s长度n,仅由0和1组成,n是偶数。

现在Tokitsukaze s成最小数量的连续子段,并且对于每个子段,每个子段中的所有数都是相同的。之后,s如果所有子段的长度都是偶数,则认为是好的。

例如,如果ss为“ 11001111 ”,将分为“ 11 ”、“ 00 ”和“ 1111 ”。它们的长度是2,2,4分别是偶数,所以“ 11001111 ”是好的。

另一个例子,如果s为“ 1110011000 ”,将分为“ 111 ”、“ 00 ”、“ 11 ”和“ 000 ”,它们的长度分别为3,2,2,3. 显然,“ 1110011000 ”不好。

Tokitsukaze 想使s改变一些位置的值. 具体来说,她可以执行任意次数的操作:改变 si 为“ 0 ”或“ 1 ”(1≤i≤n)。

你能告诉她最少的修改次数吗?同时,她还想知道最小的子段数s可以在所有操作数最少的解决方案中进行划分。

思路

计算次数的方法同上。

我们可以在每次判断2个数不同时对其进行修改,每次都修改成和左边相同。

然后在遍历求字段数。

需要注意的是当开头的两个数不同时我们可以把它们都赋值为1 或 0 ,分别求出子段数再输出最小值。

代码

 

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

void solve()
{
    int n;
    string s;
    cin >> n >> s;
    int cnt = 0;
    string s1 = s, s2 = s;
    if (s[0] != s[1])
    {
        cnt = 1;
        s1[0] = '0';
        s1[1] = '0';
        s2[0] = '1';
        s2[1] = '1';
        for (int i = 2; i < n - 1; i = i + 2)
        {
            if (s[i] != s[i + 1])
            {
                cnt++;
                if (s1[i - 1] == '1')
                {
                    s1[i] = '1';
                    s1[i + 1] = '1';
                }
                else
                {
                    s1[i] = '0';
                    s1[i + 1] = '0';
                }
                if (s2[i - 1] == '1')
                {
                    s2[i] = '1';
                    s2[i + 1] = '1';
                }
                else
                {
                    s2[i] = '0';
                    s2[i + 1] = '0';
                }
            }
        }
        int a = 0, b = 0;
        for (int i = 1; i < n; i++)
        {
            if (s1[i] != s1[i - 1])
                a++;
            if (s2[i] != s2[i - 1])
                b++;
        }
        cout << cnt << " " << min(a, b) + 1 << endl;
        return;
    }
    for (int i = 2; i < n - 1; i = i + 2)
    {
        if (s[i] != s[i + 1])
        {
            cnt++;
            if (s[i - 1] == '1')
            {
                s[i] = '1';
                s[i + 1] = '1';
            }
            else
            {
                s[i] = '0';
                s[i + 1] = '0';
            }
        }
    }
    int a = 0;
    for (int i = 1; i < n; i++)
    {
        if (s[i] != s[i - 1])
            a++;
    }
    cout << cnt << " " << a + 1 << endl;
}

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

 

标签:子段,int,s2,s1,789,Codeforces,Tokitsukaze,++,Div
来源: https://www.cnblogs.com/gosick-ll/p/16260606.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有