zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    树状数组 P3368【区间更新 单点查询】
    线段树 P3374 【单点修改 区间查询】
    线段树 P2574 【区间修改 区间查询】
    线段树 P4588 【线段树用法】
    eclipse连接mysql数据库实现怎删改查操作实例(附带源码)
    软件设计师考试 算法设计
    数据库设计
    面向对象设计
    数据流图设计
    个人总结与对老师的评价
  • 原文地址:https://www.cnblogs.com/mountaink/p/10507584.html
Copyright © 2011-2022 走看看