HDU-4622 Reincarnation 后缀数组 | Hash,维护和,扫描
2013-08-01 11:32
471 查看
题目链接: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]++。最后遍历两遍矩阵,类似扫描线,求出答案。。
后缀数组:
Hash,维护和,扫描:
题意:给一个字符串,询问某字串的不同字串的个数。
可以用后缀数组来解决,复杂度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]++。最后遍历两遍矩阵,类似扫描线,求出答案。。
后缀数组:
//STATUS:C++_AC_1218MS_248KB #include <functional> #include <algorithm> #include <iostream> //#include <ext/rope> #include <fstream> #include <sstream> #include <iomanip> #include <numeric> #include <cstring> #include <cassert> #include <cstdio> #include <string> #include <vector> #include <bitset> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <list> #include <set> #include <map> using namespace std; //using namespace __gnu_cxx; //define #define pii pair<int,int> #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define PI acos(-1.0) //typedef //typedef __int64 LL; //typedef unsigned __int64 ULL; //const const int N=2010; const int INF=0x3f3f3f3f; const int MOD=100000,STA=8000010; //const LL LNF=1LL<<60; const double EPS=1e-8; const double OO=1e15; const int dx[4]={-1,0,1,0}; const int dy[4]={0,1,0,-1}; const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; //Daily Use ... inline int sign(double x){return (x>EPS)-(x<-EPS);} template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} template<class T> inline T lcm(T a,T b,T d){return a/d*b;} template<class T> inline T Min(T a,T b){return a<b?a:b;} template<class T> inline T Max(T a,T b){return a>b?a:b;} template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} //End char s ; int num ; int sa ,t1 ,t2 ,c ,rank ,height ; int T,n,m; void build_sa(int s[],int n,int m) { int i,k,p,*x=t1,*y=t2; //第一轮基数排序 for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[i]=s[i]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; for(k=1;k<=n;k<<=1){ p=0; //直接利用sa数组排序第二关键字 for(i=n-k;i<n;i++)y[p++]=i; for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; //基数排序第一关键字 for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[y[i]]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; //根据sa和x数组计算新的x数组 swap(x,y); p=1;x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break; //已经排好序,直接退出 m=p; //下次基数排序的最大值 } } void getHeight(int s[],int n) { int i,j,k=0; for(i=0;i<=n;i++)rank[sa[i]]=i; for(i=0;i<n;i++){ if(k)k--; j=sa[rank[i]-1]; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } } int main() { // freopen("in.txt","r",stdin); int i,j,a,b,l,up,low,ans,mlen,t; scanf("%d",&T); while(T--) { scanf("%s",s); n=strlen(s); for(i=0;i<n;i++) num[i]=s[i]-'a'+1; num =0; build_sa(num,n+1,27); getHeight(num,n); scanf("%d",&m); while(m--){ scanf("%d%d",&a,&b); a--,b--; l=ans=low=mlen=0,up=b-a+1; for(i=1;i<=n && l<up;i++){ if(sa[i]<a || sa[i]>b){ low=Min(low,height[i+1]); continue; } t=b-sa[i]+1; ans+=t-Min(low,t,mlen); if(t>=mlen || (t<mlen && low<t) || low==0){ mlen=t; low=height[i+1]; } else low=Min(low,height[i+1]); l++; } printf("%d\n",ans); } } return 0; }
Hash,维护和,扫描:
//STATUS:C++_AC_1343MS_29980KB #include <functional> #include <algorithm> #include <iostream> //#include <ext/rope> #include <fstream> #include <sstream> #include <iomanip> #include <numeric> #include <cstring> #include <cassert> #include <cstdio> #include <string> #include <vector> #include <bitset> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <list> #include <set> #include <map> using namespace std; //#pragma comment(linker,"/STACK:102400000,102400000") //using namespace __gnu_cxx; //define #define pii pair<int,int> #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define PI acos(-1.0) //typedef typedef __int64 LL; typedef unsigned __int64 ULL; //const const int N=2010; const int INF=0x3f3f3f3f; //const int MOD=100000,STA=8000010; const LL LNF=1LL<<60; const double EPS=1e-8; const double OO=1e15; const int dx[4]={-1,0,1,0}; const int dy[4]={0,1,0,-1}; const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; //Daily Use ... inline int sign(double x){return (x>EPS)-(x<-EPS);} template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} template<class T> inline T lcm(T a,T b,T d){return a/d*b;} template<class T> inline T Min(T a,T b){return a<b?a:b;} template<class T> inline T Max(T a,T b){return a>b?a:b;} template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} //End char s ; int w ,ans ; int l[N<<1]; int n,m; const int MOD=4001,STA=1000010; //MOD为表长,STA为表大小 struct Hash{ int first[MOD],next[STA],size; int f[STA],sta[STA]; //sta[]存放状态,f[]为对应状态的权值 void init(){ size=0; memset(first,-1,sizeof(first)); } int find_add(int st,int ans){ //查找,如果未查找到则添加 int i,u=st%MOD; for(i=first[u];i!=-1;i=next[i]){ if(sta[i]==st){ return f[i]; //已存在状态 } } sta[size]=st; f[size]=ans; next[size]=first[u]; first[u]=size++; return f[i]; } }hs; void BKDRHash() { int i,j,hash,seed=131; for(i=0;i<n;i++){ hash=0; for(j=i;j<n;j++){ hash=hash*seed+s[j]; w[i][j]=hash&0x7fffffff; } } } int main(){ // freopen("in.txt","r",stdin); int i,j,T,d,p,a,b; scanf("%d",&T); while(T--){ scanf("%s",s); n=strlen(s); BKDRHash(); mem(ans,0); for(d=0;d<n;d++){ hs.init(); for(i=0;i<n-d;i++) hs.find_add(w[i][i+d],i); mem(l,-1); for(i=0;i<n-d;i++){ p=hs.find_add(w[i][i+d],0); ans[i+d][l[p]+1]++; ans[i+d][i+1]--; l[p]=i; } } for(i=0;i<n;i++) for(j=1;j<n;j++) ans[i][j]+=ans[i][j-1]; for(j=0;j<n;j++) for(i=1;i<n;i++) ans[i][j]+=ans[i-1][j]; scanf("%d",&m); while(m--){ scanf("%d%d",&a,&b); printf("%d\n",ans[b-1][a-1]); } } return 0; }
相关文章推荐
- HDU 4622 Reincarnation (区间不相同子串个数:字符串哈希 | 后缀数组 | 后缀自动机)
- [后缀自动机 模板题 || 字符串Hash] HDU 4622 Reincarnation
- HDU 4622 Reincarnation 后缀自动机 // BKDRHash(最优hash)
- HDU 4622 Reincarnation 后缀数组 或 后缀自动机
- hdu 4622 求区间不同子串数 后缀数组|后缀自动机|字符串hash
- HDU 4622 Reincarnation(后缀自动机)
- HDU 4622 Reincarnation Hash解法详解
- hdu 4622 Reincarnation(后缀自动机,入门级)
- hdu 4622 Reincarnation (后缀自动机)
- 字符串(后缀自动机):HDU 4622 Reincarnation
- HDU 4426 (ZOJ 3661) Palindromic Substring 后缀数组二分 + Manacher + Hash
- HDU 4622 Reincarnation(字符串hash,hashMap,区间dp)
- HDU 4622 Reincarnation 后缀自动机
- hdu 4622 后缀数组计数问题||后缀自动机
- hdu 4622 Reincarnation(hash)
- hdu 4622 Reincarnation (后缀自动机)
- HDU 4622 Reincarnation 后缀自动机
- HDU 4622 Reincarnation(后缀自动机)
- 【HDU - 4622】Reincarnation 【字符串HASH+dp 】
- HDU 4029 Distinct Sub-matrix 后缀数组 + Hash 2011年上海网络赛I题