源代码:https://github.com/abmcar/ACM/tree/master/OpenjudgeNow/Codeforces/Codeforces%20Round%20%23769%20(Div.%202)

A. ABC

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

有这么几种情况

  • 字符串大小为1,此时无法获得长度大于1的回文子串
  • 字符串的大小大于3,此时无论怎么排,都会出现"11","00","101","010"这样的回文子串
  • 长度为2,只有"11","00"是回文子串

代码:

void work()
{
    string s;
    int n;
    cin >> n;
    cin >> s;
    if (s.size() == 1)
    {
        cout << "YES" << endl;
        return;
    }
    if (s.size() >= 3)
    {
        cout << "NO" << Endl;
        return;
    }
    if (s == "11" || s == "00")
        cout << "NO" << Endl;
    else
        cout << "YES" << Endl;
}

B. Roof Construction

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

从位运算的角度看,我们可以发现在最高位相同的情况下,xor的最大值没有最高位不同的两数xor值大,

而且,我们发现必然有两个最高位不同的数排在一起,我们使用0和最高位为1的最小的数拍在一起,此时成本为2^x,成本最低,其他的数按顺序拍到两侧即可

代码:

void work()
{
    cin >> n;
    int cnt = 1;
    while (cnt * 2 < n)
        cnt *= 2;
    for (int i = cnt-1; i >= 0; i--)
        cout << i << " ";
    for (int i = cnt; i < n; i++)
     

C. Strange Test

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

我们知道操作3能够使a,b接近的更多,对于最后一次操作前的a,b,记作a1,b1

总代价:(a1-a)+(b1-b) + ((a1|b1) - b1) + 1 = a1 + (a1|b1) + (1 - a - b)

已知(1-a-b)的代价固定,我们需要做的就是使a1+(a1|b1)最小

我们可以枚举a1,从位运算的角度从高到低考虑

  • 如果 a1 为0 b 为1 则 b1 设置为 1
  • 如果 a1 为0 b 为0 则 b1 设置为 0
  • 如果 a1 为0 b 为1 则 b1 设置为 1
  • 如果 a1 为0 b 为0 则 b1 设置为 1 并停止,此时b需要通过操作2来到b1,最劣情况,因此停止

之后计算代价即可

代码:

void work()
{
    cin >> a >> b;
    int ans = b - a;
    for (int a1 = a; a1 < b; a1++)
    {
        int b1 = 0;
        for (int i = 23; i >= 0; i--)
        {
            if (b & (1 << i))
                b1 = b1 | (1 << i);
            else
            {
                if (a1 & (1 << i))
                {
                    b1 = b1 | (1 << i);
                    break;
                }
            }
        }
        ans = min(ans, a1 - a - b + (a1 | b1) + 1);
    }
    cout << ans << endl;
}

D. New Year Concert

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

可以发现gcd(1-n)的值是递减的,

如果我们固定l,可以通过二分的方法找到l,r,使得[l,r]为不满足区间

对于一个不满足区间,我们可以更改其中一个数为质数,是的该区间和包含它的区间满足

因此,我们可以枚举l,得到所有不满足区间,之后使用贪心解决这个区间覆盖问题

我们可以使用线段树来快速得到区间的gcd

代码:

cin >> n;
    nums.resize(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> nums[i];
    build(1, 1, n);
    for (int i = 1; i <= n; i++)
    {
        int nowL = i + 1;
        int nowR = n;
        int ans = i;
        while (nowL <= nowR)
        {
            int nowMid = (nowL + nowR) / 2;
            if (query(1, 1, n, i, nowMid) >= nowMid - i + 1)
            {
                ans = nowMid;
                nowL = nowMid + 1;
            }
            else
                nowR = nowMid - 1;
        }
        // cout << i << " " << ans << endl;
        if (query(1, 1, n, i, ans) == ans - i + 1)
            segs[ans].push_back(i);
    }
    int nowPos = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int it : segs[i])
        {
            // cout << i << " " << it << endl;
            if (it > nowPos)
            {
                ans++;
                nowPos = i;
            }
            // cout << nowPos << " " << ans << endl;
        }
        cout << ans << " ";
    }

Q.E.D.