题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4468
题目意思:
给你一个串r,求一个串s,使得s的前缀1+s的前缀2+s的前缀3+...+s的前缀n+s=r .
解题思路:
KMP+贪心。
初始时把r[1]赋给s[1],从r中每个字符从前至后依次匹配s,当匹配失败时,说明该字符在模式串中没有出现,由贪心思想,把它放到最后(前面满足要求的话,最短的也要从上个完全匹配开始),所以把从上一次的完全匹配的位置到该字符之间的所有字符作为新的模式串,继续匹配。
当完全匹配时,更新上次完全匹配的位置值。
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
using namespace std;
#define M 100005
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
char rr[M],pp[M];
int rn,pn,next[M];
void getnext(int s)
{
int j=next[s-1];//只需从上一个开始计算
//int j=s-1;
for(int i=s;i<=pn;i++)
{
while(j>0&&pp[j+1]-pp[i])
j=next[j];
if(pp[j+1]==pp[i])
j++;
next[i]=j;
}
return ;
}
int main()
{
int ca=0;
while(scanf("%s",rr+1)!=EOF)
{
rn=strlen(rr+1);
pp[1]=rr[1];
pn=1;
next[1]=0;
int last=1;//记录上一个完全匹配的位置
int j=0;
for(int i=1;i<=rn;i++)
{
while(j>0&&pp[j+1]-rr[i])
j=next[j];
if(pp[j+1]==rr[i])
j++;
if(j==pn) //找到了新的完全匹配
{
last=i-pn+1;
j=next[j];//往回跳一个
}
else if(j==0) //有新的字母,只能作为最后一个
{
int tmp=pn;
for(int k=last+pn;k<=i;k++)
pp[++pn]=rr[k];
getnext(tmp+1); //不是getnext(last+tmp) last是随i增加的,wa了一上午
//j=pn;
}
}
printf("Case %d: %d
",++ca,rn-last+1);
}
return 0;
}