vijos kmp next数组应用

https://vijos.org/p/1677

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

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

输出文件仅包含一行,ans,表示最短的模版长度。
样例1
样例输入1[复制]

abcabababc
样例输出1[复制]

3
限制
1秒
提示
【样例解释】
陶陶的名字是abcabababc,最短的模版是abc。按如下方式喷涂出陶陶的名字:
图片
注意,印刷只能从前向后印,不能这样印:
图片
【约定】
对于10%的数据, n≤200
对于30%的数据, n≤1000
对于100%的数据,n≤1000000

思路:

(next数组为未优化kmp算法的数组,即最大前后缀串长度数组)

对于最大的i使得next[i]=0,用前i个覆盖可以把所有字符覆盖完整。
不过考虑到覆盖的部分不可以超过整个名字(即覆盖完了以后不能多),应该沿next[len]走到第一个ans使得next[k]<上述next[i](记录未k),此ans即为所求。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 1000100;
char s[maxn];
int nextt[maxn];
int main(){
    scanf("%s",s);
    int n = strlen(s);

    for(int i=1;i<n;i++){
        int j=nextt[i];
        while( j && s[j]!=s[i] ) j=nextt[j];
        nextt[i+1]= s[j]==s[i] ? j+1 : 0;
        //printf("next[%d] = %d\n",i,nextt[i+1]);
    }
    int k;
    for(int i=n;i>=0;i--)
        if(nextt[i]==0){
            k=i;
            break;
        }
    int ans=n;
    while(nextt[ans]>=k) ans=nextt[ans];
//nextt[ans]>=k是指ans前缀位置>=k,那么前面一定有相同前缀,<k的时候如果在往前取,要么超过去,要么k的那个字母得不到。
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值