https://vjudge.net/problem/CodeForces-1138D
题目
有两个字符串s和t,都只包括字符“0”和“1”,要求调整s中字符的顺序,最大化t作为字串出现的次数。
$1 leqslant |s| leqslant 500\,000$,$1 leqslant |s| leqslant 500\,000$
题解
kmp模板题+贪心……
kmp算法得到的是每个位置的最长公共前缀后缀,所以只需要使用整个字符串的最长公共前缀后缀就可以了
先统计s中每个字符的个数,然后照着t贪心填充,如果没有把剩下的都输出,如果把t填充完了那么直接跳到前缀后面继续填充
为什么出现次数最多?因为填充完毕一次以后,最少需要填充“整个字符串长度-前缀长度”个字符,填充其他的肯定没有这个更优
时间复杂度O(n)
AC代码
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cctype> #include<cassert> #define REP(i,a,b) for(register int i=(a); i<(b); i++) #define REPE(i,a,b) for(register int i=(a); i<=(b); i++) #define PERE(i,a,b) for(register int i=(a); i>=(b); i--) using namespace std; typedef long long ll; #define MAXN 500007 int f[MAXN]; char s[MAXN], t[MAXN]; inline void getf(char *s, int l) { int t=f[0]=-1; REP(i,0,l) { while(t>=0 && s[i]!=s[t]) t=f[t]; t++; f[i+1]=t; } } int main() { scanf("%s%s", s, t); int ls=strlen(s), lt=strlen(t); int cnt[2]={0,0}; getf(t,lt); REP(i,0,ls) cnt[s[i]-'0']++; int pos=0; while(1) { if(cnt[t[pos]-'0']>0) { putchar(t[pos]); cnt[t[pos]-'0']--; pos++; if(pos==lt) pos=f[pos]; } else break; } while(0<cnt[0]--) putchar('0'); while(0<cnt[1]--) putchar('1'); putchar(' '); }