解法
这道题其实就是考察 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;
}