陶陶的名字
背景
陶陶是一个智能机器人,他能像人一样思考问题,不过由于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来源
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;
}
大概就是这个样子,如果有什么问题,或错误,请在评论区提出,谢谢。