T1 POJ3461
kmp裸题:
kmp资料可以参考http://www.tuicool.com/articles/e2Qbyyf(感谢)
#include
#include
#include
#include
using namespace std;
int next[10001];
int main()
{
char s[1000001],t[100001];
int n;
cin>>n;
for(int i=0;i
int k=0,ans=0;
scanf("%s%s",&t,&s);
int sl=strlen(s);
int tl=strlen(t);
memset(next,0,sizeof(next));
next[0]=0;
for(int i=1;i
while(k>0&&(t[i]!=t[k]))
k=next[k-1];
if(t[i]==t[k])
k++;
next[i]=k;
}
k=0;
for(int i=0;i
while(k>0&&s[i]!=t[k])
k=next[k-1];
if(s[i]==t[k])
k++;
if(k==tl)
{
k=next[k-1];
ans++;
}
}
cout<
return 0;
}
T2,manacher HDU3068
#include
#include
#include
using namespace std;
int ans[220005];
int main()
{
//freopen("t2.in","r",stdin);
//freopen("t2.out","w",stdout);
char ch[110001],s[220005];
while(scanf("%s",ch)!=EOF)
{
memset(ans,0,sizeof(ans));
memset(s,0,sizeof(s));
int cl=strlen(ch),max1=0;
s[0]='@';
s[1]='#';
for(int i=0,j=2;i
s[j]=ch[i];
s[j+1]='#';
}
s[(cl+1)*2]='$';
int sl=strlen(s);
int p=1;
for(int i=2;i
ans[i]=max(0,min(ans[2*p-i],p+ans[p]-i));
while(s[i-ans[i]-1]==s[i+ans[i]+1])
ans[i]++;
if(i+ans[i]>p+ans[p])
p=i;
if(ans[i]>max1)
max1=ans[i];
}
printf("%d\n",max1);
}
return 0;
}
T3, POJ2185 网上最常见的就是每一行的最短循环节的最小公倍数*每一列的最短循环节的最小公倍数。但是,实际上是不行的。
如: ABCDEFAB就不行,详情请参考http://blog.sina.com.cn/s/blog_69c3f0410100tyjl.html
AAAABAAA
#include
#include
#include
using namespace std;
char s[1001][80];
int f[1001];
int next[1001];
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i
scanf("%s",s[i]);
for(int j=0;j
bool pd=true;
for(int l=0;l
for(int k=1;k<=m/(j+1);k++)
{
if(l+k*(j+1)>=m)
break;
if(s[i][l]!=s[i][l+k*(j+1)])
{
pd=false;
break;
}
}
if(pd==false)
break;
}
if(pd==true)
f[j+1]++;
}
}
int width;
for(int i=1;i<=m;i++)
if(f[i]==n)
{
width=i;
break;
}
next[0]=0; int k=0;
for(int i=1;i
while(k>0&&strcmp(s[i],s[k])) k=next[k-1];
if(!strcmp(s[i],s[k])) k++;
next[i]=k;
}
printf("%d\n",(n-next[n-1])*width);
return 0;
}
T4.HDU4333 这道题目最好的方法是用拓展kmp,经过观察,其实就是求每一位的后缀与自身的最长公共前缀,这个显然可以用扩展kmp处理,但是开始的时候我超时了,后来在网上看到别人把这个串后面再接上本身,以它为主串,然后以自身为模板串进行扩展kmp,这样处理把时间复杂度降到了线性的,最后要注意的一个问题就是如何避免重复了,我们可以用普通的kmp求出此串的最小循环节,如果构成完整的循环,那么我们要算的就是循环节长度的情况了。
但是,我用了后缀数组的倍增法。按理来说应该也可以,但不知为什么RE了
#include
#include
#include
#include
using namespace std;
const int N = int(400005);
int cmp(int *r,int a,int b,int l,int g){
return (r[a]==r[b]) && (r[(a+l)%g]==r[(b+l)%g]);
}
int y[N],sa[N];
bool bo[400005];
int wa[N],wb[N],ws1[N],wv[N];
void da(char *r,int sa[],int n,int m,int t1){
memset(ws1,0,sizeof(ws1));
int i,j,p=0,*x=wa,*y=wb,*t;
for(i=0;i
for(i=0;i
ws1[x[i]=r[i]]++;
}
for(i=1;i
for(i=n-1;i>=0;i--)
sa[--ws1[x[i]]]=i; //预处理长度为1
for(j=1;j
if(j>=n*2||p>=n)
break;
p=0;
for(i=0;i
y[p++]=sa[i]-j;
while(y[p-1]<0)
y[p-1]+=n;
while(y[p-1]>n)
y[p-1]-=n;//利用长度J的,按第二关键字排序
}
for(i=0;i
for(i=0;i
for(i=0;i
for(i=1;i<=m;i++)
ws1[i]+=ws1[i-1];
for(i=n-1;i>=0;i--)
sa[--ws1[wv[i]]]=y[i];
t=x;
x=y;
y=t;
x[sa[0]]=1;
for(p=1,i=1;i
x[sa[i]]=cmp(y,sa[i-1],sa[i],j,n)?p:++p;
}
}
int bz=x[0];
int big=0,small=0,same=0;
for(int i=0;i
if(x[i]>bz&&!bo[x[i]])
{
big++;
bo[x[i]]=true;
}
if(x[i]
small++;
bo[x[i]]=true;
}
if(x[i]
same++;
bo[x[i]]=true;
}
}
printf("%s %d%c %d %d %d\n","Case",t1,':',small,same,big);
}
char str[N];
int main(){
// freopen("t4.in","r",stdin);
// freopen("t4.out","w",stdout);
int t1;
char str[N];
scanf("%d",&t1);
for(int i=1;i<=t1;i++)
{
memset(bo,false,sizeof(bo));
int te=i;
scanf("%s",str);
int n = strlen(str);
str[n]=0;
da(str,sa,n,76,te);
}
//cout<
}
T5,hdu3613,manacher/EKMP
manacher,求出简单的回文串的变形,先将到每个位置的价值预处理出来然后将字符串跑一边马拉车,我枚举切每个位置的价值和,如现在枚举的是切第三个的位置,则判断一下前三个位置能否形成回文串,那么我们只用判断第二个位置的len1如果等于三则说明是回文串就醒了。
EKMP,将s1翻转得到s2,如果s1[i]---s1[len-1]=s2[0]---s[(len-1)-i],那么,这一段就是回文串,反过来也是一样。这可以用EKMP实现。
#include
#include
#include
#include
#include
#include
#include
#include
#include
T6,水题,跳过。