UVALive4513 Stammering Aliens(哈希法,后缀数组)

来源:互联网 发布:如何编写安卓软件 编辑:程序博客网 时间:2024/06/05 08:32
 

 

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12580

 

【思路】

       求出现次数不小于k次的最长可重复子串和最后的出现位置。

       法一:

              后缀数组,二分长度,划分height。时间复杂度为O(nlogn)

       法二:

              Hash法。构造字符串的hash函数,二分长度,求出hash(i,L)后排序,判断是否存在超过k个相同hash 值得块即可。时间为O(nlog2n).

       注意划分height一定要精确且如果m=1需要特判(对于该模板来说)。

 

【代码1】

 

 1 //193ms  2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6  7 const int maxn = 80000+10;  8  9 int s[maxn];10 int sa[maxn],c[maxn],t[maxn],t2[maxn];11 void build_sa(int m,int n) {12     int i,*x=t,*y=t2;13     for(i=0;i<m;i++) c[i]=0;14     for(i=0;i<n;i++) c[x[i]=s[i]]++;15     for(i=1;i<m;i++) c[i]+=c[i-1];16     for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;17     for(int k=1;k<=n;k<<=1) {18         int p=0;19         for(i=n-k;i<n;i++) y[p++]=i;20         for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;21         for(i=0;i<m;i++) c[i]=0;22         for(i=0;i<n;i++) c[x[y[i]]]++;23         for(i=0;i<m;i++) c[i]+=c[i-1];24         for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];25         swap(x,y);26         p=1; x[sa[0]]=0;27         for(i=1;i<n;i++) 28             x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;29         if(p>=n) break;30         m=p;31     }32 }33 int rank[maxn],height[maxn];34 void getHeight(int n) {35     int i,j,k=0;36     for(i=0;i<=n;i++) rank[sa[i]]=i;37     for(i=0;i<n;i++) {38         if(k) k--;39         j=sa[rank[i]-1];40         while(s[j+k]==s[i+k]) k++;41         height[rank[i]]=k;42     }43 }44 int limit,n,pos;45 bool can(int L) {    //一定要注意划分height数组的准确性 46     pos=-1;47     int cnt=1,mx=sa[1];48     for(int i=2;i<=n;i++) {49         mx=max(mx,sa[i]);50         if(height[i]<L) cnt=1,mx=sa[i];51         else {52             if(++cnt>=limit) pos=max(pos,mx);53         }54     }55     return pos>=0;56 }57 58 char expr[maxn];59 int main() {60     //freopen("in.in","r",stdin);61     //freopen("out.out","w",stdout);62     while(scanf("%d",&limit)==1 && limit) {63         scanf("%s",expr);64         n=strlen(expr);65         for(int i=0;i<n;i++) s[i]=expr[i]; s[n]=0;66         67         build_sa('z'+1,n+1);68         getHeight(n);69         70         if(limit==1) { printf("%d 0\n",n); continue; }71         int L=1,R=n+1;72         while(L<R) {73             int M=L+(R-L+1)/2;74             if(can(M)) L=M; else R=M-1;75         }76         if(!can(L)) printf("none\n");77         else printf("%d %d\n",L,pos);78     }79     return 0;80 }
da

 

【代码2】

 

 1 //1628ms 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7  8 typedef unsigned long long ULL; 9 const int maxn = 80000+10;10 const int x = 233;11 12 ULL hash[maxn],xp[maxn],H[maxn];13 int m,n;14 char s[maxn];15 16 int cmp(const int& a,const int& b) {17     return hash[a]<hash[b] || (hash[a]==hash[b] && a<b);18 }19 int pos,rank[maxn];20 bool can(int L) {21     pos=-1;22     for(int i=0;i<n-L+1;i++) hash[i]=H[i]-H[i+L]*xp[L],rank[i]=i;23     sort(rank,rank+n-L+1,cmp);24     int cnt=0;25     for(int i=0;i<n-L+1;i++) {26         if(!i || hash[rank[i]]!=hash[rank[i-1]]) cnt=0;27         if(++cnt>=m) pos=max(pos,rank[i]);28     }29     return pos>=0;30 }31 32 int main() {33     //freopen("in.in","r",stdin);34     //freopen("outr.out","w",stdout);35     while(scanf("%d",&m)==1 && m) {36         scanf("%s",s);37         n=strlen(s);38         39         H[n]=0,xp[0]=1;40         for(int i=n-1;i>=0;i--) H[i]=H[i+1]*x+s[i]-'a';41         for(int i=1;i<=n;i++) xp[i]=xp[i-1]*x;42         43         if(!can(1)) printf("none\n");44         else {45             int L=1,R=n+1;46             while(L<R) {47                 int M=L+(R-L+1)/2;48                 if(can(M)) L=M;  else R=M-1;49             }50             can(L);51             printf("%d %d\n",L,pos);52         }53     }54     return 0;55 }
hash

 

0 0