D. Camp Schedule
今天!终于学会 K M P KMP KMP了!!
题意:给你 01 01 01串 s s s, t t t,任意改变串 s s s的字符顺序,求构造一个字符串 c c c满足 t t t在 c c c中的出现次数最多。
题解:首先求出串 s s s的 0 0 0和 1 1 1数量,其次利用 K M P KMP KMP里的 n e x t next next数组,如果会 K M P KMP KMP的话,就知道,实际上 n e x t next next数组就是模式串的公共前缀后缀的最大长度表往右移了一格并将初始位置赋值为 − 1 -1 −1。因此我们可以先构造一个串 t t t,然后去通过最长公共前缀后缀继续构造接下来的字符,最后再把剩余的 01 01 01加上去即可。这样就可以满足串 t t t的出现次数最多。比如 s = 101101 ,    t = 110 s = 101101,\;t= 110 s=101101,t=110,那么我们就可以先构造出 110 110 110,然后根据最长公共前缀和后缀为 0 0 0,那么接下来就需要模式串回溯到开头,然后添加 c = 110110 c = 110110 c=110110。因为是利用了已有的最长公共前缀和后缀,所以我们可以保证这样做是让 t t t出现次数最多的。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
const int N = 5E5+10;
int nxt[N];
string s,t;
void getNext()
{
int j = 0, k = -1, len = t.length();
nxt[0] = -1;
while(j < len) {
if(k == -1 || t[j] == t[k]) {
++j, ++k;
if(t[j] != t[k]) {
nxt[j] = k;
}else{
nxt[j] = nxt[k];
}
}else{
k = nxt[k];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
cin >> s >> t;
getNext();
int one = 0, zero = 0;
for(int i = 0; i < s.length(); ++i) {
one += s[i] - '0';
zero += !(s[i] - '0');
}
int it = 0;
string ans = "";
while(zero > 0 && one > 0) {
if(t[it] == '0') {
if(zero > 0) {
zero--;
ans += '0';
}else{
break;
}
}else{
if(one > 0) {
one--;
ans += '1';
}else{
break;
}
}
it++;
if(it == t.length()) {
it = nxt[it];
}
}
for(int i = 0; i < zero; ++i) ans += '0';
for(int i = 0; i < one; ++i) ans += '1';
cout << ans << endl;
return 0;
}