CF1138D(545,div2) Camp Schedule

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('\n');

}

猜你喜欢

转载自www.cnblogs.com/sahdsg/p/12299013.html
今日推荐