【字符串】【模拟】【CodeForces】Many Equal Substrings

34 篇文章 0 订阅
11 篇文章 0 订阅

【题目】http://codeforces.com/contest/1029/problem/A

【题意】给出子串t和子串出现的次数k,求最短的父串s

【思路】每次加上子串,看结尾是不是子串的前缀,是的话补全子串,操作直到k。

【代码】

 AC代码:

#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;

const int M=2500+5;
const int inf=1e9+5;

char a[M];
char b[M];

int main()
{
    int n,k;
    cin>>n>>k;
    cin>>a;
    if(n!=1)
    {
        k--;
        int p;
        strcpy(b,a);
        while(k--)
        {
            //只要每次从父串尾巴找到子串的前缀补全即可
            int flag=1;
            for(int i=strlen(b)-n+1; i<strlen(b); i++)
            {
                flag=0;
                for(int j=0,k=i; k<strlen(b); j++,k++)
                {
                    if(b[k]!=a[j])
                    {
                        flag=1;
                        break;
                    }
                    p=j;
                }
                if(flag==0)
                    break;
            }
            if(flag==0)
            {
                for(int j=p+1,k=strlen(b); j<n; j++,k++)
                {
                    b[k]=a[j];
                }
            }
            else
            {
                strcat(b,a);
            }
        }
        cout<<b<<endl;
    }
    else
    {
        for(int i=0; i<k; i++)
            cout<<a;
    }
    return 0;
}

NC代码: 

#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;

const int M=2500+5;
const int inf=1e9+5;

char a[M];
char b[M];

int main()
{
    int n,k;
    cin>>n>>k;
    cin>>a;
    if(n!=1)
    {
        k--;
        int flag=0, flag2=0;
        int head=0,headt=0,fh=0;
        strcpy(b,a);
        //求fh(下1次头要跳多远)
        //从i=1往后(跳过i=0)找子串出现的位置
        for(int i=1; i<strlen(b); i++)//枚举开头
        {
            flag=0;
            for(int j=0,k=i; k<strlen(b); k++,j++)//枚举子串每1位
            {
                //k<父串长度能控制结尾是因为
                //父串一定从只剩最长1个子串长度的地方开始枚举
                fuck(j);
                if(b[k]!=a[j])//如果不满足就要退出,换i再做
                {
                    flag2=0;
                    flag=1;
                    fh=0;
                    break;
                }
                if(flag2==0)//f2让只有子串匹配位置的开头能改变fh
                {
                    flag2=1;
                    fh=k;
                }
            }
            if(flag==0)//flag为0代表当前情况找到了子串
                break;
        }
        if(fh==0)
            fh=strlen(b);
        fuck(fh);
        while(k--)
        {
            int len=strlen(b);
            flag=0,flag2=0;
            head=headt;//headt在上一次循环中被改变
            int p;
            for(int i=head+1; i<len; i++)
                //下1次寻找从上1次匹配成功的下1位开始找
            {
                flag=0;
                for(int j=0,k=i; k<len; k++,j++)
                {
                    if(b[k]!=a[j])
                    {
                        flag2=0;
                        flag=1;
                        headt=head+fh;//子串没有循环的话,下1个head当然是head+fh
                        break;
                    }
                    if(flag2==0)
                    {
                        flag2=1;
                        headt=k;//否则head就是匹配的开始位置
                    }
                    p=j;//存还没有补到父串上的剩余子串断点
                }
                if(flag==0)//flag是0代表匹配到了位置
                    break;
            }
            if(flag==0)//补全父串
            {
                for(int j=p+1,k=len; j<n; j++,k++)
                {
                    b[k]=a[j];
                }
            }
            else//没找着就直接加上
            {
                strcat(b,a);
            }
        }
        cout<<b<<endl;
    }
    else
    {
        for(int i=0; i<k; i++)
            cout<<a;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值