HDU-4622 Reincarnation 后缀数组 | Hash,维护和,扫描

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622

  题意:给一个字符串,询问某字串的不同字串的个数。

  可以用后缀数组来解决,复杂度O(n)。先求出倍增算法求出sa数组,然后DP求出Height数组,对于每个询问,重构sa数组,这里重构可以利用整个串的sa数组来得到,但是这里截取的字串,可能顺序会变化,看一个例子:cacbe

  排序为:acbe,be,cacbe,cbe,e   得到字串[0,2]的排序是:acbe(1),cacbe(0),cbe(2)   但cac的实际排序是:ac(1),c(2),cac(0)  后缀0和2的顺序反了,因此我们要保留的是在子串里面长度尽量长的串。。。

  Hash做法就是先用Hash把所有的字串取出来,可以用BKDRHash,基本认为不产生冲突,产生冲突的概率很小,然后维护一个矩阵ans[i][j],表示字串[j,i]的不同字串的个数。处理所有串,对于相同的串[l1,r1],[l2,r2]...那么询问[L,R],l1<L<=l2,r1<=R<=r2,则ans[r2][r1+1]++,ans[r2][l2+1]++。最后遍历两遍矩阵,类似扫描线,求出答案。。

后缀数组:

  1 //STATUS:C++_AC_1218MS_248KB
  2 #include <functional>
  3 #include <algorithm>
  4 #include <iostream>
  5 //#include <ext/rope>
  6 #include <fstream>
  7 #include <sstream>
  8 #include <iomanip>
  9 #include <numeric>
 10 #include <cstring>
 11 #include <cassert>
 12 #include <cstdio>
 13 #include <string>
 14 #include <vector>
 15 #include <bitset>
 16 #include <queue>
 17 #include <stack>
 18 #include <cmath>
 19 #include <ctime>
 20 #include <list>
 21 #include <set>
 22 #include <map>
 23 using namespace std;
 24 //using namespace __gnu_cxx;
 25 //define
 26 #define pii pair<int,int>
 27 #define mem(a,b) memset(a,b,sizeof(a))
 28 #define lson l,mid,rt<<1
 29 #define rson mid+1,r,rt<<1|1
 30 #define PI acos(-1.0)
 31 //typedef
 32 //typedef __int64 LL;
 33 //typedef unsigned __int64 ULL;
 34 //const
 35 const int N=2010;
 36 const int INF=0x3f3f3f3f;
 37 const int MOD=100000,STA=8000010;
 38 //const LL LNF=1LL<<60;
 39 const double EPS=1e-8;
 40 const double OO=1e15;
 41 const int dx[4]={-1,0,1,0};
 42 const int dy[4]={0,1,0,-1};
 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 44 //Daily Use ...
 45 inline int sign(double x){return (x>EPS)-(x<-EPS);}
 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
 49 template<class T> inline T Min(T a,T b){return a<b?a:b;}
 50 template<class T> inline T Max(T a,T b){return a>b?a:b;}
 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
 55 //End
 56 char s[N];
 57 int num[N];
 58 int sa[N],t1[N],t2[N],c[N],rank[N],height[N];
 59 int T,n,m;
 60 
 61 void build_sa(int s[],int n,int m)
 62 {
 63     int i,k,p,*x=t1,*y=t2;
 64     //第一轮基数排序
 65     for(i=0;i<m;i++)c[i]=0;
 66     for(i=0;i<n;i++)c[x[i]=s[i]]++;
 67     for(i=1;i<m;i++)c[i]+=c[i-1];
 68     for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
 69     for(k=1;k<=n;k<<=1){
 70         p=0;
 71         //直接利用sa数组排序第二关键字
 72         for(i=n-k;i<n;i++)y[p++]=i;
 73         for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
 74         //基数排序第一关键字
 75         for(i=0;i<m;i++)c[i]=0;
 76         for(i=0;i<n;i++)c[x[y[i]]]++;
 77         for(i=1;i<m;i++)c[i]+=c[i-1];
 78         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
 79         //根据sa和x数组计算新的x数组
 80         swap(x,y);
 81         p=1;x[sa[0]]=0;
 82         for(i=1;i<n;i++)
 83             x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 84         if(p>=n)break;   //已经排好序,直接退出
 85         m=p;     //下次基数排序的最大值
 86     }
 87 }
 88 
 89 void getHeight(int s[],int n)
 90 {
 91     int i,j,k=0;
 92     for(i=0;i<=n;i++)rank[sa[i]]=i;
 93     for(i=0;i<n;i++){
 94         if(k)k--;
 95         j=sa[rank[i]-1];
 96         while(s[i+k]==s[j+k])k++;
 97         height[rank[i]]=k;
 98     }
 99 }
100 
101 int main()
102 {
103  //   freopen("in.txt","r",stdin);
104     int i,j,a,b,l,up,low,ans,mlen,t;
105     scanf("%d",&T);
106     while(T--)
107     {
108         scanf("%s",s);
109         n=strlen(s);
110         for(i=0;i<n;i++)
111             num[i]=s[i]-'a'+1;
112         num[n]=0;
113         build_sa(num,n+1,27);
114         getHeight(num,n);
115 
116         scanf("%d",&m);
117         while(m--){
118             scanf("%d%d",&a,&b);
119             a--,b--;
120             l=ans=low=mlen=0,up=b-a+1;
121             for(i=1;i<=n && l<up;i++){
122                 if(sa[i]<a || sa[i]>b){
123                     low=Min(low,height[i+1]);
124                     continue;
125                 }
126                 t=b-sa[i]+1;
127                 ans+=t-Min(low,t,mlen);
128                 if(t>=mlen || (t<mlen && low<t) || low==0){
129                     mlen=t;
130                     low=height[i+1];
131                 }
132                 else low=Min(low,height[i+1]);
133                 l++;
134             }
135             printf("%d\n",ans);
136         }
137     }
138     return 0;
139 }

 

Hash,维护和,扫描:

  1 //STATUS:C++_AC_1343MS_29980KB
  2 #include <functional>
  3 #include <algorithm>
  4 #include <iostream>
  5 //#include <ext/rope>
  6 #include <fstream>
  7 #include <sstream>
  8 #include <iomanip>
  9 #include <numeric>
 10 #include <cstring>
 11 #include <cassert>
 12 #include <cstdio>
 13 #include <string>
 14 #include <vector>
 15 #include <bitset>
 16 #include <queue>
 17 #include <stack>
 18 #include <cmath>
 19 #include <ctime>
 20 #include <list>
 21 #include <set>
 22 #include <map>
 23 using namespace std;
 24 //#pragma comment(linker,"/STACK:102400000,102400000")
 25 //using namespace __gnu_cxx;
 26 //define
 27 #define pii pair<int,int>
 28 #define mem(a,b) memset(a,b,sizeof(a))
 29 #define lson l,mid,rt<<1
 30 #define rson mid+1,r,rt<<1|1
 31 #define PI acos(-1.0)
 32 //typedef
 33 typedef __int64 LL;
 34 typedef unsigned __int64 ULL;
 35 //const
 36 const int N=2010;
 37 const int INF=0x3f3f3f3f;
 38 //const int MOD=100000,STA=8000010;
 39 const LL LNF=1LL<<60;
 40 const double EPS=1e-8;
 41 const double OO=1e15;
 42 const int dx[4]={-1,0,1,0};
 43 const int dy[4]={0,1,0,-1};
 44 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 45 //Daily Use ...
 46 inline int sign(double x){return (x>EPS)-(x<-EPS);}
 47 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
 48 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
 49 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
 50 template<class T> inline T Min(T a,T b){return a<b?a:b;}
 51 template<class T> inline T Max(T a,T b){return a>b?a:b;}
 52 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
 53 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
 54 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
 55 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
 56 //End
 57 
 58 char s[N];
 59 int w[N][N],ans[N][N];
 60 int l[N<<1];
 61 int n,m;
 62 
 63 const int MOD=4001,STA=1000010;  //MOD为表长,STA为表大小
 64 
 65 struct Hash{
 66     int first[MOD],next[STA],size;
 67     int f[STA],sta[STA];   //sta[]存放状态,f[]为对应状态的权值
 68     void init(){
 69         size=0;
 70         memset(first,-1,sizeof(first));
 71     }
 72     int find_add(int st,int ans){   //查找,如果未查找到则添加
 73         int i,u=st%MOD;
 74         for(i=first[u];i!=-1;i=next[i]){
 75             if(sta[i]==st){
 76                 return f[i];   //已存在状态
 77             }
 78         }
 79         sta[size]=st;
 80         f[size]=ans;
 81         next[size]=first[u];
 82         first[u]=size++;
 83         return f[i];
 84     }
 85 }hs;
 86 
 87 void BKDRHash()
 88 {
 89     int i,j,hash,seed=131;
 90     for(i=0;i<n;i++){
 91         hash=0;
 92         for(j=i;j<n;j++){
 93             hash=hash*seed+s[j];
 94             w[i][j]=hash&0x7fffffff;
 95         }
 96     }
 97 }
 98 
 99 int main(){
100  //   freopen("in.txt","r",stdin);
101     int i,j,T,d,p,a,b;
102     scanf("%d",&T);
103     while(T--){
104         scanf("%s",s);
105         n=strlen(s);
106         BKDRHash();
107 
108         mem(ans,0);
109         for(d=0;d<n;d++){
110             hs.init();
111             for(i=0;i<n-d;i++)
112                 hs.find_add(w[i][i+d],i);
113             mem(l,-1);
114             for(i=0;i<n-d;i++){
115                 p=hs.find_add(w[i][i+d],0);
116                 ans[i+d][l[p]+1]++;
117                 ans[i+d][i+1]--;
118                 l[p]=i;
119             }
120         }
121         for(i=0;i<n;i++)
122             for(j=1;j<n;j++)
123                 ans[i][j]+=ans[i][j-1];
124         for(j=0;j<n;j++)
125             for(i=1;i<n;i++)
126                 ans[i][j]+=ans[i-1][j];
127 
128         scanf("%d",&m);
129         while(m--){
130             scanf("%d%d",&a,&b);
131             printf("%d\n",ans[b-1][a-1]);
132         }
133     }
134     return 0;
135 }

 

posted @ 2013-08-01 11:32  zhsl  阅读(623)  评论(0编辑  收藏  举报