T1 POJ3461
kmp裸题:
kmp资料可以参考http://www.tuicool.com/articles/e2Qbyyf(感谢)
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
int next[10001];
int main()
{
char s[1000001],t[100001];
int n;
cin>>n;
for(int i=0;i<n;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<tl;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<sl;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<<ans<<endl;
}
return 0;
}
T2,manacher HDU3068
#include<cstdio>
#include<algorithm>
#include<cstring>
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<cl;i++,j+=2)
{
s[j]=ch[i];
s[j+1]='#';
}
s[(cl+1)*2]='$';
int sl=strlen(s);
int p=1;
for(int i=2;i<sl;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<iostream>
#include<cstdio>
#include<cstring>
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<n;i++)
{
scanf("%s",s[i]);
for(int j=0;j<m;j++)
{
bool pd=true;
for(int l=0;l<j+1;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<n;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<cstdio>
#include<iostream>
#include<cstring>
#include<ctime>
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<m;i++)
ws1[i]=0;
for(i=0;i<n;i++)
{
ws1[x[i]=r[i]]++;
}
for(i=1;i<m;i++)
ws1[i]+=ws1[i-1];
for(i=n-1;i>=0;i--)
sa[--ws1[x[i]]]=i; //预处理长度为1
for(j=1;j<n*2,p<n;j*=2,m=p) //通过已经求出的长度J的SA,来求2*J的SA
{
if(j>=n*2||p>=n)
break;
p=0;
for(i=0;i<n;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<n;i++)
wv[i]=x[y[i]];
for(i=0;i<m;i++)
ws1[i]=0;
for(i=0;i<n;i++)
ws1[wv[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<n;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<n;i++)
{
if(x[i]>bz&&!bo[x[i]])
{
big++;
bo[x[i]]=true;
}
if(x[i]<bz&&!bo[x[i]])
{
small++;
bo[x[i]]=true;
}
if(x[i]<bz&&!bo[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<<clock();
return 0;
}
T5,hdu3613,manacher/EKMP
manacher,求出简单的回文串的变形,先将到每个位置的价值预处理出来然后将字符串跑一边马拉车,我枚举切每个位置的价值和,如现在枚举的是切第三个的位置,则判断一下前三个位置能否形成回文串,那么我们只用判断第二个位置的len1如果等于三则说明是回文串就醒了。
EKMP,将s1翻转得到s2,如果s1[i]---s1[len-1]=s2[0]---s[(len-1)-i],那么,这一段就是回文串,反过来也是一样。这可以用EKMP实现。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<ctime>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 99999999
using namespace std;
const int MAX=500000+10;
char s1[MAX],s2[MAX];
int next1[MAX],extend1[MAX],extend2[MAX];
int sum[MAX],val[27],j;
void get_next(char *a,int len){
int k=0,i=1;
next1[0]=len;
while(k+1<len&&a[k]==a[k+1]) k++;
next1[1]=k;
k=1;
for(int i=2;i<len;i++)
{
int u=k+next1[k];
if(u>i+next1[i-k]) next1[i]=next1[i-k];
else
{
for(j=max(0,u-i);a[i]==a[i+j];j++);
next1[i]=j;
k=i;
}
}
}
void EKMP(char *a,char *b,int *extend,int len){
get_next(a,len);
int k=0,i=0;
while(k<len && a[k] == b[k])++k;
extend[0]=k;
k=0;
while(++i<len){
int maxr=k+extend[k]-1;
extend[i]=min(next1[i-k],max(maxr-i+1,0));
while(i+extend[i]<len && a[extend[i]] == b[i+extend[i]])++extend[i];
if(i+extend[i]>k+extend[k])k=i;
}
}
int main()
{
freopen("t5.in","r",stdin);
freopen("t5.out","w",stdout);
int t;
cin>>t;
for(int i=0;i<t;i++)
{
memset(sum,0,sizeof(sum));
memset(next1,0,sizeof(next1));
memset(extend1,0,sizeof(extend1));
memset(extend2,0,sizeof(extend2));
for(int i=0;i<26;i++)
{
scanf("%d",&val[i]);
}
scanf("%s",&s1);
int len=strlen(s1);
for(int i=1;i<=len;++i)
{
sum[i]=sum[i-1]+val[s1[i-1]-'a'];
s2[i-1]=s1[len-i];
}
EKMP(s1,s2,extend1,len);
EKMP(s2,s1,extend2,len);
int ans=0,temp=0;
for(int i=1;i<len;++i){
if(extend1[len-i] == i)temp+=sum[i];//表示前i个字符是
if(extend2[i] == len-i)temp+=sum[len]-sum[i];//表示后len-i个字符是
if(temp>ans)ans=temp;
temp=0;
}
cout<<ans<<endl;
}
cout<<clock();
return 0;
}
T6,水题,跳过。