「Codeforces 1138D」Camp Schedule 题解

解法

这道题其实就是考察 KMP 算法中 Next 数组的使用。题意转换过来大致就是:

给定两个 01 串,构造一个长度跟第一个串相同且 1 的个数相同的串,且保证第二个串的出现次数最多,出现可以重叠。

可以重叠的话,我们可以考虑贪心:后缀如果能跟前缀重合,那么出现的次数就有可能会变多。求出 Next 数组便是求出最长重合前后缀。我们可以循环添加字串的后缀,同时判断是否需要填充多余的 1 或 0。这样就搞定了。

代码

// D.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 501000;
string A, B;
int totA, totB, nxt[MAX_N];
void getNext(string str)
{
    string tmp = " " + str;
    for (int i = 2; i <= tmp.length() - 1; i++)
    {
        int j = nxt[i - 1];
        while (j && tmp[j + 1] != tmp[i])
            j = nxt[j];
        if (tmp[j + 1] == tmp[i])
            nxt[i] = j + 1;
        else
            nxt[i] = 0;
    }
}
int main()
{
    cin >> A >> B;
    getNext(B);
    for (int i = 0; i < A.length(); i++)
        totA += A[i] - '0';
    for (int i = 0; i < B.length(); i++)
        totB += B[i] - '0';
    if (A.length() < B.length() || totA < totB)
        cout << A, exit(0);
    A = " " + A, B = " " + B;
    int ans = A.length();
    for (int i = 1, j = 0; i < A.length(); i++)
    {
        if (totA && B[j + 1] == '1')
            totA--, A[i] = '1', j++;
        else if (B[j + 1] == '0')
            A[i] = '0', j++;
        else
        {
            ans = i;
            break;
        }
        if (j == B.length() - 1)
            j = nxt[j];
    }
    for (int i = ans; i < A.length(); i++)
        A[i] = '0';
    while (totA)
    {
        ans--;
        if (A[ans] == '1')
            totA++;
        A[ans] = '1', totA--;
    }
    cout << A.substr(1);
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *