源代码:ACM/OpenjudgeNow/Codeforces at master · abmcar/ACM (github.com)

A. Sorting Parts

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

如果前半段之中存在一个数大于后半段的其中一个数,则不可能完成排序

可以使用一个前缀最大值和后缀最小值,枚举前半段的长度即可

代码:

void work()
{
    cin >> n;
    vector<int> nums(n);
    vector<int> preMax(n), aftMin(n);
    for (int i = 0; i < n; i++)
        cin >> nums[i];
    preMax[0] = nums[0];
    aftMin[n - 1] = nums[n - 1];
    for (int i = 1; i < n; i++)
        preMax[i] = max(nums[i], preMax[i - 1]);
    for (int i = n - 2; i >= 0; i--)
        aftMin[i] = min(nums[i], aftMin[i + 1]);
    for (int i = n - 2; i >= 0; i--)
        if (preMax[i] > aftMin[i + 1])
        {
            // cout << preMax[i] << "    "<< aftMin[i] << endl;
            // cout <<i << endl;
            cout << "YES" << endl;
            return;
        }
    cout << "NO" << Endl;
}

B.MEX and Array

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

把问题分开来看,如果我们得到了一个子串,那么他最佳分割时的mex是多少?

我们知道任何非0数的单独的mex为0,0的单独mex为1,{0,1}的mex为2

发现分为长度为1的子段时,mex和最小,此时mex和为0的个数

因此我们枚举每一个区间,判断其中0的个数即可,因为n只有100,所以可以暴力

代码:

int getValue(vector<int> nowNums)
{
    int nowAns = nowNums.size();
    for (int it : nowNums)
        if (it == 0)
            nowAns++;
    return nowAns;
}

void work()
{
    cin >> n;
    ans = 0;
    vector<int> nums(n);
    for (int i = 0; i < n; i++)
        cin >> nums[i];
    for (int len = 1; len <= n; len++)
    {
        for (int str = 0; str+len <= n; str++)
        {
            vector<int> temp(len);
            for (int nowPos = 0; nowPos < len; nowPos++)
            {
                temp[nowPos] = nums[str+nowPos];
            }
            ans += getValue(temp);
        }
    }
    cout << ans << endl;
} 

C.Andrew and Stones

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

最简单的情况,中间的数全部是2的倍数,我们可以把其中1个放首位,1个放末尾

如果中间有不是1的倍数,怎么办?

如果中间还有别的数进行操作,我们可以把这堆石子的其中一个给不是2的倍数的石堆

如果没有别的数进行操作,且该石堆可以操作1次以上,总长度大于4,可以让该石堆给另一个中间的石堆2个,这个石堆再给原石堆一个

代码:

void work()
{
    cin >> n;
    vector<int> nums(n), opts(n);
    for (int i = 0; i < n; i++)
        cin >> nums[i];
    int ans = 0;
    int oriAns = 0;
    int st = 0;
    for (int i = 1; i < n - 1; i++)
    {
        opts[i] = (nums[i] - nums[i] % 2) / 2;
        nums[i] = nums[i] % 2;
        ans += opts[i];
        st += (nums[i] == 1);
    }
    oriAns = ans;
    for (int i = 1; i < n - 1; i++)
    {
        if (nums[i] == 0)
            continue;
        if (oriAns - opts[i] > 0 || (n >= 4 && opts[i] >= 1))
        {
            ans++;
        }
        else
        {
            cout << -1 << endl;
            return;
        }
    }
    cout << ans << endl;
}

D.Yet Another Minimization Problem

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

通过计算,化简可得,成本和数组的和成正相关
A5EF59F38E97E6C6B9FCF87124A0A8A2.png
由基本不等式可以想到,二者差越小,成本和越小

剩下的问题可以用01背包来解决

代码:

void work()
{
    cin >> n;
    vector<int> na(n), nb(n);
    vector<pair<int, int>> nd(n);
    for (int i = 0; i < n; i++)
        cin >> na[i];
    for (int i = 0; i < n; i++)
        cin >> nb[i];
    unordered_map<int, int> dp[n];
    dp[0][na[0]] = na[0] - nb[0];
    dp[0][nb[0]] = nb[0] - na[0];
    for (int i = 1; i < n; i++)
    {
        for (auto it : dp[i - 1])
        {
            dp[i][it.first + na[i]] = 1e15;
            dp[i][it.first + nb[i]] = 1e15;
        }
        for (auto it : dp[i - 1])
        {
            dp[i][it.first + na[i]] = min(dp[i][it.first + na[i]], it.second + na[i] - nb[i]);
            dp[i][it.first + nb[i]] = min(dp[i][it.first + nb[i]], it.second + nb[i] - na[i]);
        }
    }
    int d = 1e15;
    int totA, totB;
    for (auto it : dp[n - 1])
    {
        if (abs(it.second) < d)
        {
            d = abs(it.second);
            totA = it.first;
            totB = it.first - it.second;
        }
    }
    int ans = 0;
    for (int i = 0; i < n; i++)
        ans += na[i] * na[i] + nb[i] * nb[i];
    ans *= (n - 2);
    ans += totA * totA + totB * totB;
    cout << ans << endl;
}

Q.E.D.