codeforces1137B kmp(fail的妙用)

题目传送门

题意:给出$s$和$t$两个串,让你构造出一个答案串,使得答案串中的01数量和s一样,并且使$t$在答案串中作为子串出现次数最多。

思路:

  要想出现的次数尽可能多,那么就要重复的利用,哪一部分是可以重复利用的呢?就是前缀和后缀相同的部分,然后我们就想到了$kmp$算法中$fail$函数就是求这个东西的,那么我们先对t串fail一遍得到$next$数组,然后先使前缀出现一次,然后就使除了前缀以外的后缀尽可能出现的多,这样得到的答案串必定是最多的,最后把剩余的01输出就可以了。

  记住扫描字符串的for循环千万不要用(i<strlen(s))当条件,否则就是个$n2$的算法了(你会tle15)。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=500010;
int n,f[maxn],a,b;
char s[maxn],p[maxn];
void fail(){
    f[0]=-1;
    for(int j=1;j<n;j++)
    {
        for(int i=f[j-1];;i=f[i])
        {
            if(p[j]==p[i+1]){
                f[j]=i+1;
                break;
            }else if(i==-1)
            {
                f[j]=-1;
                break;
            }
        }
    }
    for(int i=0;i<n;i++)f[i]++;
}
int main(){
    while(scanf("%s",s)!=EOF)
    {
        scanf("%s",p);
        n=strlen(p);
        fail();
        a=b=0;
        int si=strlen(s);
        for(int i=0;i<si;i++)
        {
            if(s[i]=='0')a++;
            else b++;
        }
        int xx=0,yy=0;
        for(int i=0;i<f[n-1];i++)
        {
            if(p[i]=='0')xx++;
            else yy++;
        
        }
        if(a>=xx&&b>=yy)
        {
            for(int i=0;i<f[n-1];i++)printf("%c",p[i]);
            a-=xx,b-=yy;
            int xxx=0,yyy=0;
            for(int i=f[n-1];i<n;i++)
            {
                if(p[i]=='0')xxx++;
                else yyy++;
            }
            int flag=0;
            while(a>0&&b>0)
            {
                if(a<xxx||b<yyy)break;
                for(int i=f[n-1];i<n;i++)
                {
                    printf("%c",p[i]);
                }
                a-=xxx,b-=yyy;
            }
            while(a>0){
                printf("0");
                a--;
            }
            while(b>0){
                printf("1");
                b--;
            }
            puts("");
        }else{
            printf("%s
",s);
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/mountaink/p/10507584.html