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 }