当前位置: 代码迷 >> 综合 >> CodeForces 1137B Camp Schedule(KMP的next数组)
  详细解决方案

CodeForces 1137B Camp Schedule(KMP的next数组)

热度:20   发布时间:2023-12-13 19:22:17.0

KMP的next数组, 参考:https://blog.csdn.net/weixin_42102584/article/details/88360361
题目意思:
给出两个0-1字符串s和t,问如何重排s可以使得产生的新字符串中包括最多的连续子串t,输出重排结果。
本题要点:
1、对字符串 t 计算 next 数组, next[lent] 就是字符串t的最长的前后缀, 假如 next[lent] == idx,
坐标范围 [1, idx] 这部分字符串假设是 x
坐标范围 [idx + 1, lent] 这部分字符串假设是 y,
xyyyyyy, 显然此种构造方式是最省字母的让 tt 多次出现的构造方式
2、用len0, len1 来统计字符串s中, ‘0’ 和 '1’出现的次数:
输出 调整后的 字符串 ans 时候,输出1, --len1, 输出0, --len0。
尽量每 lent 个字符,凑够 一个字符串 t。具体输出看代码。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 500010;
char s[MaxN], t[MaxN], ans[MaxN];
int Next[MaxN];
int lens, lent, len0, len1, len;void calc_next()
{
    Next[1] = 0;for(int i = 2, j = 0; i <= lent; ++i){
    while(j > 0 && t[i] != t[j + 1])j = Next[j];if(t[i] == t[j + 1])++j;Next[i] = j;}
}void solve()
{
    len0 = 0, len1 = 0;for(int i = 1; i <= lens; ++i){
    if(s[i] == '0')++len0;else++len1;}calc_next();len = lent - Next[lent];	//字符串 t的最长前后缀长度for(int i = 1, j = 1; i <= lens; ++i, ++j){
    if(t[j] == '1' && len1){
    ans[i] = '1';--len1;}else if(t[j] == '0' && len0){
    ans[i] = '0';--len0;}else{
    if(len1){
    ans[i] = '1';--len1;}else{
    ans[i] = '0';--len0;}}if(j == lent)	j = Next[j];}printf("%s\n", ans + 1);
}int main()
{
    scanf("%s%s", s + 1, t + 1);lens = strlen(s + 1), lent = strlen(t + 1);if(lens < lent){
    printf("%s\n", s + 1);return 0;}solve();return 0;
}/* 101101 110 *//* 110110 */
  相关解决方案