HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

#include <iostream>#include <stdio.h>#include <string.h>#include <stack>#include <queue>#include <map>#include <set>#include <vector>#include <math.h>#include <bitset>#include <algorithm>#include <climits>using namespace std;#define LS 2*i#define RS 2*i+1#define UP(i,x,y) for(i=x;i<=y;i++)#define DOWN(i,x,y) for(i=x;i>=y;i–)#define MEM(a,x) memset(a,x,sizeof(a))#define W(a) while(a)#define gcd(a,b) __gcd(a,b)#define LL long long#define N 2005#define MOD 1000000007#define INF 0x3f3f3f3f#define EXP 1e-8#define rank rank1int wa[N],wb[N],wsf[N],wv[N],sa[N];int rank[N],height[N],s[N],a[N];char str[N],str1[N],str2[N];#define F(x) ((x)/3+((x)%3==1?0:tb))#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)//sa:字典序中排第i位的起始位置在str中第sa[i]//rank:就是str第i个位置的后缀是在字典序排第几//height:字典序排i和i-1的后缀的最长公共前缀int cmp(int *r,int a,int b,int k){return r[a]==r[b]&&r[a+k]==r[b+k];}void getsa(int *r,int *sa,int n,int m)//n要包含末尾添加的0{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++) wsf[i]=0;for(i=0; i<n; i++) wsf[x[i]=r[i]]++;for(i=1; i<m; i++) wsf[i]+=wsf[i-1];for(i=n-1; i>=0; i–) sa[–wsf[x[i]]]=i;p=1;j=1;for(; p<n; j*=2,m=p){for(p=0,i=n-j; i<n; i++) y[p++]=i;for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0; i<n; i++) wv[i]=x[y[i]];for(i=0; i<m; i++) wsf[i]=0;for(i=0; i<n; i++) wsf[wv[i]]++;for(i=1; i<m; i++) wsf[i]+=wsf[i-1];for(i=n-1; i>=0; i–) sa[–wsf[wv[i]]]=y[i];t=x;x=y;y=t;x[sa[0]]=0;for(p=1,i=1; i<n; i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;}}void getheight(int *r,int n)//n不保存最后的0{int i,j,k=0;for(i=1; i<=n; i++) rank[sa[i]]=i;for(i=0; i<n; i++){if(k)k–;elsek=0;j=sa[rank[i]-1];while(r[i+k]==r[j+k])k++;height[rank[i]]=k;}}int Log[N];int best[30][N];void setLog(){Log[0] = -1;for(int i=1; i<N; i++){Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;}}void RMQ(int n) //初始化RMQ{for(int i = 1; i <= n ; i ++) best[0][i] = height[i];for(int i = 1; i <= Log[n] ; i ++){int limit = n – (1<<i) + 1;for(int j = 1; j <= limit ; j ++){best[i][j] = min(best[i-1][j] , best[i-1][j+(1<<i>>1)]);}}}int LCP(int a,int b) //询问a,b后缀的最长公共前缀{a ++;int t = Log[b – a + 1];return min(best[t][a] , best[t][b – (1<<t) + 1]);}int t,n,m;int solve(int l,int r,int n){int ans = (r-l+1)*(r-l+2)/2;int last = -1;int cnt = r-l+1;for(int i = 1; i<=n; i++){if(!cnt) break;if(sa[i]<l || sa[i]>r) continue;cnt–;if(last == -1){last = i;continue;}int a = last;int b = i;if(a>b) swap(a,b);int lcp = LCP(a,b);int la = r-sa[last]+1;//区间内该串的尾部int lb = r-sa[i]+1;if(la>=lb && lcp>=lb);//la包含lb了,,那么就用la继续往后比较,借此保持字典序,来模拟得到该区间的所有heightelse last = i;ans-=min(lcp,min(la,lb));}return ans;}int main(){int i,j,k,len,l,r;scanf("%d",&t);setLog();W(t–){scanf("%s",str);scanf("%d",&m);len = strlen(str);for(i = 0; i<len; i++)s[i] = str[i]-'a'+1;s[len] = 0;getsa(s,sa,len+1,30);getheight(s,len);RMQ(len);while(m–){scanf("%d%d",&l,&r);printf("%d\n",solve(l-1,r-1,len));}}return 0;}

生活不要太劳累,弄得自己很疲惫,快乐幸福多体会,

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

相关文章:

你感兴趣的文章:

标签云: