【vijos1677】【KMP】陶陶的名字

陶陶的名字

背景

陶陶是一个智能机器人,他能像人一样思考问题,不过由于IQ问题,他给自己取了一个很长很长的名字。

描述

某一天,陶陶想把自己的名字涂在墙上。由于他的名字太长,为了省事,他从自己名字的开头截取了一段作为模板。我们不妨设这个模板的长度为l,陶陶的名字的长度为L,那么有1≤l≤L。然后陶陶会用这个模板进行若干次喷涂,喷出自己的名字(后一次喷涂会覆盖前一次喷涂的结果,例如当前墙上已经有abc三个字符,那么如果在c处进行喷涂,就会得到ababc)。陶陶喷涂名字总是从前向后喷的,假设陶陶喷涂了k次,这k次喷涂按时间顺序第i次喷涂的位置是s[i],那么s[i]< s[i+1]。

输入格式

输入文件的仅包含一行,为陶陶的名字。

输出格式

输出文件仅包含一行,ans,表示最短的模版长度。

样例输入

abcabababc

样例输出

3

限制

1秒
对于10%的数据, n≤200
对于30%的数据, n≤1000
对于100%的数据,n≤1000000

来源

https://vijos.org/p/1677

KMP的题,在vijos上看到的,感觉很神奇,就做了。
大概说一下思路吧,首先很容易想到的就是找到最后一个fail指针为0的点,但是还有一个问题我刚开始也没有想到,就是如果那样子取的话最后可能会多出来一截,就不行了
我们设最后一个为0的点是last,可以证明所有i>last的[1..i]的字符串如果不管最后多出来都是可以覆盖完的,所以我们就让k=len,然后沿着fail指针跳,跳到最小一个>last的就是答案了

程序如下,很好理解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define INF 2100000000
#define ll long long
#define clr(x)  memset(x,0,sizeof(x))
#define clrmax(x)  memset(x,127,sizeof(x))

using namespace std;

inline int read()
{
    char c;
    int ret=0;
    while(!(c>='0'&&c<='9'))
        c=getchar();
    while(c>='0'&&c<='9')
    {
        ret=(c-'0')+(ret<<1)+(ret<<3);
        c=getchar();
    }
    return ret;
}

#define M 1000005

char s[M];
int f[M],mi[M],last,ans;

int main()
{
    freopen("in.txt","r",stdin);
    scanf("%s",s+1);
    s[0]=' ';
    int len=strlen(s)-1;
    for(int i=1;i<=len;i++)
    {
        int j=f[i-1];
        while(j>0&&s[j+1]!=s[i])j=f[j];
        if(s[j+1]!=s[i]||j+1==i)last=i;
        else f[i]=j+1;
    }
    int k=len;
    while(k>=last)
    {
        if(f[k]<=last)
            ans=k;
        k=f[k];
    }
    cout<<ans;
}

大概就是这个样子,如果有什么问题,或错误,请在评论区提出,谢谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值