Educational Codeforces Round 159 (Rated for Div. 2) | “朝闻道”知识分享大赛

重生带我走 2023-12-04 13:33:09

这是我参加朝闻道知识分享大赛的第二十一篇文章。

下面是对 codeforces Educational Codeforces Round 159 的前三道题的讲解,坑点挺多的,不过却都可以作为经验教训。

A Binary Imbalance

题意:

​ 给定仅包含 01 的字符串,每次可以往字符串某个位置插入 0 或者 1,如果相邻两个字符相同,则插入1,否则插入0,问是否可以在任意次操作下,使得字符串中,0 的个数严格大于 1 的个数。

思路:

​ 显然,如果字符串中包含有相邻的 01,那么一定可以创造出无限个0,因此剩余的就是全 0 或者全 1 的情况了,直接分类讨论即可,代码如下:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)

mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}

int main()
{
    IOS;
    cf (_)
    {
        int n;
        cin >> n;

        string s;
        cin >> s;

        bool ok = false;
        for (int i = 0; i + 1 < n; i++)
        {
            if (s[i + 1] != s[i])
            {
                ok = true;
                break;
            }
        }

        if (ok) cout << "YES\n";
        else if (s[0] == '1')   cout << "NO\n";
        else    cout << "YES\n";
    }
    return 0;
}

B Getting Points

题意:大学生在大学期间需要修够一定的学分才可以毕业,已知获取学分有 2 个途径,分别是听课和完成习题。已知习题是每周可以做一道,做完可以获得固定的学分,而课程是每天可以上一节,上完也是获取固定的学分。但一天最多只能同时上一次课和完成不超过2个的习题,问在修满学分的情况下,最多可以休息多少天?

思路:

显然,如果学习一天的话一定是尽可能多学点,如果能学1节课与2个练习,则优先考虑,进而考虑1节课和仅剩1个练习,最后是每天1个练习,按照这种思路模拟即可。

解法一:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)

mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}

void solve()
{
    ll n, p, l, t;
    cin >> n >> p >> l >> t;

    ll cnt = n / 7 + (n % 7 != 0); // cnt个任务
    
    // 先3天,后全是1天
    if (cnt % 2 == 0)
    {
        ll days = cnt / 2;
        ll every = t * 2 + l;
        if (days * every >= p)
        {
            ll l = 1, r = days;
            while (l < r)
            {
                ll mid = l + r >> 1;
                if (mid * every >= p)   r = mid;
                else    l = mid + 1;
            }
            cout << (n - l) << "\n";
        }
        else
        {
            p -= days * every;
            ll last = p / l + (p % l != 0);
            cout << n - (days + last) << "\n";
        }
    }
    else
    {
        ll days = cnt / 2;
        ll every = t * 2 + l;
        //是不是前3种的天
        if (days * every >= p)
        {
            ll l = 1, r = days;
            while (l < r)
            {
                ll mid = l + r >> 1;
                if (mid * every >= p)   r = mid;
                else    l = mid + 1;
            }
            cout << (n - l) << "\n";
        }
        else
        {
            p -= days * every;
            if (p <= l + t) cout << n - (days + 1) << "\n";
            else
            {
                p -= l + t;
                ll last = p / l + (p % l != 0);
                cout << n - (days + 1 + last) << "\n";
            }
        }
    }
}

int main()
{
    IOS;
    int t;
    cin >> t;

    while (t--)
    {
        solve();
    }
    
    return 0;
}

解法二:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)

mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}

void solve()
{
    ll n, p, l, t;
    cin >> n >> p >> l >> t;

    ll cnt = n / 7 + (n % 7 != 0);
    ll days = cnt / 2 + (cnt % 2 != 0);
    ll mx = days * l + cnt * t;

    if (mx >= p) // mx够
    {
        ll last_day_sum = l + (cnt % 2 != 0 ? t : 2 * t);
        if (mx - last_day_sum < p)  cout << n - days << "\n";
        else
        {
            ll l2 = 1, r2 = days - 1;
            ll every = 2 * t + l;
            while (l2 < r2)
            {
                ll mid = l2 + r2 >> 1;
                if ((__int128_t)mid * every >= p)    r2 = mid;
                else    l2 = mid + 1;
            }
            
            cout << n - l2 << "\n";
        }
    }   
    else
    {
        ll last = p - mx;
        ll last_day = last / l + (last % l != 0);
        cout << n - (days + last_day) << "\n";
    }
}

int main()
{
    IOS;
    int t;
    cin >> t;

    while (t--)
    {
        solve();
    }
    
    return 0;
}

C Insert and Equalize

题意: 给定 n 个数,每个数互不相同,你需要加入一个与其余 n 个数不同的新数,然后选择一个固定的数 x,每次往 n + 1 个数的数组中,选取一个数令其 + x,最终需要让所有数相同,问最少操作次数?

思路:

显然,有最大公约数的概念。即选择的 x 是这 n 个数的最大公约数,那么其次第 n + 1 个数怎么选择呢,通过模拟找规律或证明可知,选择的数一定是小于原 n 个数组中最大的那个数,找到第一个小于最大数的且满足相差是最大公约数(d)的倍数,因此最后计算答案贡献即可。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)

mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}

int main()
{
    IOS;
    cf (_)
    {
        int n;
        cin >> n;

        vector<ll> a(n + 2);
        map<ll, ll> mp;
        for (int i = 1; i <= n; i++)    cin >> a[i], mp[a[i]]++;

        if (n == 1)
        {
            cout << 1 << "\n";
            continue;
        }

        sort(a.begin() + 1, a.end() - 1);

        ll d = 0;
        for (int i = 1; i + 1 <= n; i++)
        {
            ll t = a[i + 1] - a[i];
            d = gcd(d, t);
        }

        // cout << d << "\n";

        ll res = 0;
        for (ll i = a[n]; i >= -1e18; i -= d)
        {
            if (!mp.count(i))
            {
                res = i;
                break;
            }
        }

        assert(d != 0);

        ll ans = 0;
        a[n + 1] = res;
        for (int i = 1; i <= n + 1; i++)
        {
            ans += abs(a[i] - a[n]) / d;
        }

        cout << ans << "\n";
    }
    return 0;
}
...全文
148 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

1,040

社区成员

发帖
与我相关
我的任务
社区描述
中南民族大学CSDN高校俱乐部聚焦校内IT技术爱好者,通过构建系统化的内容和运营体系,旨在将中南民族大学CSDN社区变成校内最大的技术交流沟通平台。
经验分享 高校 湖北省·武汉市
社区管理员
  • c_university_1575
  • WhiteGlint666
  • wzh_scuec
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

欢迎各位加入中南民族大学&&CSDN高校俱乐部社区(官方QQ群:908527260),成为CSDN高校俱乐部的成员具体步骤(必填),填写如下表单,表单链接如下:
人才储备数据库及线上礼品发放表单邀请人吴钟昊:https://ddz.red/CSDN
CSDN高校俱乐部是给大家提供技术分享交流的平台,会不定期的给大家分享CSDN方面的相关比赛以及活动或实习报名链接,希望大家一起努力加油!共同建设中南民族大学良好的技术知识分享社区。

注意:

1.社区成员不得在社区发布违反社会主义核心价值观的言论。

2.社区成员不得在社区内谈及政治敏感话题。

3.该社区为知识分享的平台,可以相互探讨、交流学习经验,尽量不在社区谈论其他无关话题。

试试用AI创作助手写篇文章吧