SCOI2012喵星球的点名--后缀数组

来源:互联网 发布:在线看熊片的软件 编辑:程序博客网 时间:2024/05/01 11:52

求子串的问题,本来想找一道AC自动机的题做,结果这题的字符有10000种,会比较麻烦,所以考虑后缀数组。

我部分细节处理感觉非常的暴力,所以非常的慢。。。。。。。。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn=200005;int read(){int x=0;char c=getchar();while((c<'0')||(c>'9'))c=getchar();while((c>='0')&&(c<='9'))x=x*10+c-'0',c=getchar();return x;}int a[maxn],s[maxn],id[maxn],vis[maxn],ans[maxn],slen=0;int sa[maxn],x[maxn],y[maxn],c[maxn];void get_sa(){    int N=slen,M=10002,k=1;    for(int i=1;i<=N;i++)c[x[i]=s[i]]++;    for(int i=1;i<=M;i++)c[i]+=c[i-1];    for(int i=N;i>=1;i--)sa[c[x[i]]--]=i;    while(1){    int l=0;    for(int i=0;i<=M;i++)c[i]=0;    for(int i=N-k+1;i<=N;i++)y[++l]=i;    for(int i=1;i<=N;i++)if(sa[i]>k)y[++l]=sa[i]-k;    for(int i=1;i<=N;i++)c[x[i]]++;    for(int i=1;i<=M;i++)c[i]+=c[i-1];    for(int i=N;i>=1;i--)sa[c[x[y[i]]]--]=y[i];    l=0,memcpy(y,x,sizeof(x));    for(int i=1;i<=N;i++)    x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+k]==y[sa[i-1]+k]))?l:++l;    if(l==N)break;    M=l,k<<=1;}}int cmp(int *a,int len,int *s,int pos){ for(int i=1;i<=len;i++){if(pos+i-1>slen)return 1;else if(a[i]<s[pos+i-1])return -1;else if(a[i]>s[pos+i-1])return 1;}return 0;}int find(int *a,int len,bool type){    int l=1,h=slen,res=0;    while(l<=h){    int mid=(l+h)>>1,tmp=cmp(a,len,s,sa[mid]);    if(!tmp){res=mid;if(type)l=mid+1;else h=mid-1;}else if(tmp>0)l=mid+1;else h=mid-1;}return res;}int query(int *a,int len,int now){int l=find(a,len,0),r=find(a,len,1),res=0;if((!l)||(!r))return 0;for(int i=l;i<=r;i++)if(vis[id[sa[i]]]!=now)vis[id[sa[i]]]=now,++ans[id[sa[i]]],++res;return res;}int main(){    int n=read(),m=read(),len;    for(int i=1;i<=2*n;i++){    len=read();    s[++slen]=10002;    while(len--){    s[++slen]=read();    id[slen]=((i+1)>>1);}}get_sa();    for(int i=1;i<=m;i++){    len=read();    for(int j=1;j<=len;j++)a[j]=read();    printf("%d\n",query(a,len,i));}for(int i=1;i<=n;i++)    printf("%d%c",ans[i],i==n?'\n':' ');    return 0;}
今天学了好久啊,字符串算法太难了。

1 1
原创粉丝点击