您的位置:首页 > 其它

hdu 4333 扩展kmp

2015-04-29 10:45 357 查看
题意:题意:给定一个数字<=10^100000,一次将该数的第一位放到放到最后一位,求所有组成的不同的数比原数小的个数,相等的个数,大的个数

扩展kmp入门题

假如有431,则复制为2个,即,431431,


对该字符串和原穿求ekmp求得extend,求得最长公共前缀,3,0,0,3,0,0,extend【1】=3即表示匹配3位则刚好为原串的长度,则相等,extend【2】=0表示并未存在相同前缀,这时就拿3和4比较,假设extend【2】=1,即存在一个相同前缀,那么只需要和第二位比较即可。

总体来说就是避免不必要的比较

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
const int MAXN=2000010;

int nextt[MAXN];
int extend[MAXN];

void pre_EKMP(char x[],int m,int nextt[])
{
nextt[0]=m;
int j=0;
while(j+1<m && x[j]==x[j+1])j++;
nextt[1]=j;
int k=1;
for(int i=2;i<m;i++)
{
int p=nextt[k]+k-1;
int L=nextt[i-k];
if(i+L<p+1)nextt[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<m && x[i+j]==x[j])j++;
nextt[i]=j;
k=i;
}
}
}
void EKMP(char x[],char y[])
{
int n=strlen(y);
int m=strlen(x);
pre_EKMP(x,m,nextt);
int j=0;
while(j<n && j<m && x[j]==y[j])j++;
extend[0]=j;
int k=0;
for(int i=1;i<n;i++)
{
int p=extend[k]+k-1;
int L=nextt[i-k];
if(i+L<p+1)extend[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<n && j<m && y[i+j]==x[j])j++;
extend[i]=j;
k=i;
}
}
}
void getnextt(char T[],int len)
{
int j,k;
j=0;k=-1;
nextt[0]=-1;
while(j<len)
{
if(k==-1 || T[j]==T[k])
nextt[++j]=++k;
else k=nextt[k];
}
}
char str1[MAXN],str2[MAXN];
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
int T;
int iCase=0;
scanf("%d",&T);
while(T--)
{
iCase++;
scanf("%s",str1);
int len=strlen(str1);
strcpy(str2,str1);
strcat(str2,str1);
EKMP(str1,str2);
/*for(int i=0;i<len*2;i++)
{
printf("%d ",extend[i]);
}
printf("\n");*/
int cnt1=0,cnt2=0,cnt3=0;
for(int i=0;i<len;i++)
{
if(extend[i]>=len)cnt2++;
else
{
if(str2[i+extend[i]]<str1[extend[i]])cnt1++;
else cnt3++;
}
}
getnextt(str1,len);
int t=len-nextt[len];
int tol=1;
if(len%t==0)tol=len/t;
printf("Case %d: %d %d %d\n",iCase,cnt1/tol,cnt2/tol,cnt3/tol);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: