首页 > 代码库 > hdu 5008
hdu 5008
因为一看到有关子串就主动的联想后缀数组
所有后缀的前缀去重后就是所有子串(好像是废话)
这样就可以得到每个后缀的子串个数。
二分查找到第k个所在的位置。
在二分处理所有可以出现该串的sa区间。
最小就是维护sa数组。
1 //rank从0开始 2 //sa从1开始,因为最后一个字符(最小的)排在第0位 3 //high从2开始,因为表示的是sa[i-1]和sa[i] 4 #include <cstdio> 5 #include <cstring> 6 #include <iostream> 7 #include <algorithm> 8 #define root 1,n,1 9 #define lson l,mid,rt<<1 10 #define rson mid+1,r,rt<<1|1 11 #define M 120010 12 #define INF 10000007 13 using namespace std; 14 typedef long long LL; 15 LL rank[M],sa[M],X[M],Y[M],high[M],init[M]; 16 LL buc[M]; 17 struct SegmentTree{ 18 LL Min[M << 2]; 19 void pushup(LL rt){ 20 Min[rt] = min(Min[rt<<1],Min[rt<<1|1]); 21 } 22 void build(LL l,LL r,LL rt){ 23 if(l == r){ 24 Min[rt] = sa[l]; 25 return; 26 } 27 LL mid = (l + r) >> 1; 28 build(lson); 29 build(rson); 30 pushup(rt); 31 } 32 LL query(LL L,LL R,LL l,LL r,LL rt){ 33 if(L <= l && r <= R){ 34 return Min[rt]; 35 } 36 LL mid = (l + r) >> 1; 37 LL ans = INF; 38 if(L <= mid) ans = min(query(L,R,lson),ans); 39 if(mid + 1 <= R) ans = min(query(L,R,rson),ans); 40 return ans; 41 } 42 }; 43 SegmentTree sgt; 44 void calhigh(LL n) { 45 LL i , j , k = 0; 46 for(i = 1 ; i <= n ; i++) rank[sa[i]] = i; 47 for(i = 0 ; i < n ; high[rank[i++]] = k) 48 for(k?k--:0 , j = sa[rank[i]-1] ; init[i+k] == init[j+k] ; k++); 49 } 50 bool cmp(LL *r,LL a,LL b,LL l) { 51 return (r[a] == r[b] && r[a+l] == r[b+l]); 52 } 53 void suffix(LL n,LL m = 128) { 54 LL i , l , p , *x = X , *y = Y; 55 for(i = 0 ; i < m ; i ++) buc[i] = 0; 56 for(i = 0 ; i < n ; i ++) buc[ x[i] = init[i] ] ++; 57 for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; 58 for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i; 59 for(l = 1,p = 1 ; p < n ; m = p , l *= 2) { 60 p = 0; 61 for(i = n-l ; i < n ; i ++) y[p++] = i; 62 for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l; 63 for(i = 0 ; i < m ; i ++) buc[i] = 0; 64 for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++; 65 for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; 66 for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i]; 67 for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++) 68 x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++; 69 } 70 calhigh(n-1);//后缀数组关键是求出high,所以求sa的时候顺便把rank和high求出来 71 } 72 73 74 //当需要反复询问两个后缀的最长公共前缀时用到RMQ 75 LL Log[M]; 76 LL best[20][M]; 77 void initRMQ(LL n) {//初始化RMQ 78 for(LL i = 1; i <= n ; i ++) best[0][i] = high[i]; 79 for(LL i = 1; i <= Log[n] ; i ++) { 80 LL limit = n - (1<<i) + 1; 81 for(LL j = 1; j <= limit ; j ++) { 82 best[i][j] = min(best[i-1][j] , best[i-1][j+(1<<i>>1)]); 83 } 84 } 85 } 86 LL lcp(LL a,LL b) {//询问a,b后缀的最长公共前缀 87 //a = rank[a]; b = rank[b]; 88 //if(a > b) swap(a,b); 89 //a ++; 90 if(a>b)return 0; 91 LL t = Log[b - a + 1]; 92 return min(best[t][a] , best[t][b - (1<<t) + 1]); 93 } 94 95 char str[M]; 96 LL dlen[M]; 97 98 void getlen(LL n,LL len){ 99 //dlen[1]=len-sa[1];100 for(LL i=1;i<=n;i++){101 dlen[i]=len-sa[i]-high[i];102 //printf("%d ",dlen[i]);103 }104 //cout<<endl;105 for(LL i=1;i<=n;i++){106 dlen[i]+=dlen[i-1];107 }108 }109 void findK(LL n,LL k,LL &start,LL &len){110 //printf("%I64d %I64d\n",k,dlen[n]);111 if(k>dlen[n]||k<=0){112 start=len=0;113 return ;114 }115 LL l=1,r=n;116 while(l<=r){117 LL mid=(l+r)>>1;118 if(dlen[mid]>=k) r=mid-1;119 else l=mid+1;120 }121 start=l;122 len=k-dlen[start-1]+high[start];123 //printf("start:%I64d len:%I64d\n",start,len);124 }125 LL findLcp(LL start,LL len,LL n){126 LL l=start + 1,r=n;127 while(l<=r){128 LL mid=(l+r)>>1;129 if(lcp(start+1,mid)>=len)l=mid+1;130 else r=mid-1;131 }132 //printf("start:%I64d r:%I64d\n",start,r);133 return sgt.query(start,r,root);134 }135 int main() {136 //预处理每个数字的Log值,常数优化,用于RMQ137 LL l,r,q;138 LL v,u;139 LL start,llen;140 Log[0] = -1;141 for(LL i = 1; i < M ; i ++) {142 Log[i] = (i&(i-1)) ? Log[i-1] : Log[i-1] + 1 ;143 }144 //*******************************************145 // n为数组长度,下标0开始146 // 将初始数据,保存在init里,并且保证每个数字都比0大147 // m = max{ init[i] } + 1148 // 一般情况下大多是字符操作,所以128足够了149 //*******************************************150 151 while(scanf("%s",str)!=EOF){152 l = r = 0;153 LL n=strlen(str);154 for(LL i=0;i<n;i++)init[i]=str[i];155 init[n]=0;156 suffix(n+1);157 initRMQ(n);158 getlen(n,n);159 sgt.build(root);160 scanf("%I64d",&q);161 for(LL i=1;i<=q;i++){162 scanf("%I64d",&v);163 u=(l^r^v)+1;164 findK(n,u,start,llen);165 //printf("u:%I64d\n",u);166 if(llen==0&&start==0){167 l=0,r=0;168 printf("0 0\n");169 continue;170 }171 LL ans=findLcp(start,llen,n);172 l=ans;r=ans+llen-1;173 l++;r++;174 printf("%I64d %I64d\n",l,r);175 }176 }177 // init[n] = 0;178 // suffix(n+1,m);179 }180 /*181 acab182 10183 2184 */
hdu 5008
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。