题意:
给出两个串,求这两个串结合的结果,规则是把重复的部分删去,这两个串都可以做头和尾,那么结果首先选择结合后串最短的,第二选择字典序最小的。
题解:
扩展kmp求最长公共前前缀,对于任意i,如果extend[i]+i==len说明这个是最长的后缀可以输出!!。只要O(n)枚举i即可
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
//typedef long long lld;
const int oo=0x3f3f3f3f;
//const lld OO=1LL<<61;
const int MOD=10007;
const int maxn=100000+10;
char s1[maxn],s2[maxn],str1[maxn<<1],str2[maxn<<1];
int next[maxn],extend[maxn];
void get_extend(char T[],int len)
{
int k=0;
next[k]=len;
while(k<len-1&&T[k]==T[k+1])k++;
next[1]=k;
k=1;
for(int i=2;i<len;i++)
{
int p=k+next[k]-1,L=next[i-k];
if(i+L-1>=p)
{
int j=max(p-i+1,0);
while(i+j<len&&T[i+j]==T[j])j++;
next[i]=j;
k=i;
}
else next[i]=L;
}
}
void Ekmp(char S[],char T[],int lenS,int lenT)
{
get_extend(T,lenT);
int k=0;
while(k<lenT&&k<lenS&&S[k]==T[k])k++;
extend[0]=k;
k=0;
for(int i=1;i<lenS;i++)
{
int p=k+extend[k]-1,L=next[i-k];
if(i+L-1>=p)
{
int j=max(p-i+1,0);
while(i+j<lenS&&j<lenT&&S[i+j]==T[j])j++;
extend[i]=j;
k=i;
}
else extend[i]=L;
}
}
int main()
{
int len1,len2,pos;
while(scanf("%s%s",s1,s2)!=EOF)
{
len1=strlen(s1);
len2=strlen(s2);
Ekmp(s1,s2,len1,len2);
int pos=len1;
for(int i=0;i<len1;i++)
{
if(extend[i]+i==len1)
{
pos=i;
break;
}
}
for(int i=0;i<pos;i++)
str1[i]=s1[i];
strcpy(str1+pos,s2);
Ekmp(s2,s1,len2,len1);
pos=len2;
for(int i=0;i<len2;i++)
{
if(extend[i]+i==len2)
{
pos=i;
break;
}
}
for(int i=0;i<pos;i++)
str2[i]=s2[i];
strcpy(str2+pos,s1);
len1=strlen(str1);
len2=strlen(str2);
if(len1<len2)
puts(str1);
else if(len1>len2)
puts(str2);
else
{
if(strcmp(str1,str2)<0)
puts(str1);
else
puts(str2);
}
}
return 0;
}
/**
asdf sdfg
asdf ghjk
*/