HDU2459 后缀数组+RMQ
2016-01-24 16:04
183 查看
题目大意:
在原串中找到一个拥有连续相同子串最多的那个子串
比如dababababc中的abababab有4个连续的ab,是最多的
如果有同样多的输出字典序最小的那个
这里用后缀数组解决问题:
枚举连续子串的长度l , 那么从当前位置0出发每次递增l,拿 i 和 i+l 开头的后缀求一个前缀和val , 求解依靠RMQ 得到区间 rank(i),rank(i+l)
那么连续的子串个数应该是val/l+1
但是由于你不一定是从最正确的位置出发,那么我们就需要不断将这个i往前推l位,直到某一位字符不匹配,推移的过程中,可能与形成连续串多出的
部分形成一个新的子串,那么个数应该加1,且不断更新推移过程中的rank值,尽量取到rank值小的开头的字符串
在原串中找到一个拥有连续相同子串最多的那个子串
比如dababababc中的abababab有4个连续的ab,是最多的
如果有同样多的输出字典序最小的那个
这里用后缀数组解决问题:
枚举连续子串的长度l , 那么从当前位置0出发每次递增l,拿 i 和 i+l 开头的后缀求一个前缀和val , 求解依靠RMQ 得到区间 rank(i),rank(i+l)
那么连续的子串个数应该是val/l+1
但是由于你不一定是从最正确的位置出发,那么我们就需要不断将这个i往前推l位,直到某一位字符不匹配,推移的过程中,可能与形成连续串多出的
部分形成一个新的子串,那么个数应该加1,且不断更新推移过程中的rank值,尽量取到rank值小的开头的字符串
#include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <algorithm> #include <iostream> using namespace std; typedef long long ll; const int N = 100010; int r , sa , _rank , height ; int wa , wb , wv , wsf ; int cmp(int *r , int a , int b , int l){return r[a]==r[b]&&r[a+l]==r[b+l];} void da(int *r , int *sa , int n , int m) { 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; for(j=1,p=1;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]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } void callHeight(int *r , int *sa , int n) { int i,j,k=0; for(i=1;i<=n;i++) _rank[sa[i]]=i; for(i=0;i<n;height[_rank[i++]]=k) for(k?k--:0,j=sa[_rank[i]-1];r[i+k]==r[j+k];k++); return; } int dp[N<<1][18] , n; char s ; void ST() { memset(dp , 0x3f , sizeof(dp)); for(int i=1 ; i<=n ; i++)dp[i][0]=height[i]; for(int k=1 ; (1<<k)<=n ; k++){ for(int i=1 ; i<=n ; i++){ dp[i][k] = min(dp[i][k-1] , dp[i+(1<<(k-1))][k-1]); } } } int RMQ(int s , int t) { int d = t-s+1; int k = (int)log2(d*1.0); // cout<<s<<" "<<t<<" "<<k<<" "<<t-(1<<k)+1<<endl; return min(dp[s][k] , dp[t-(1<<k)+1][k]); } int RMQPOS(int x , int y) { // cout<<"cal pos: "<<x<<" "<<y<<" "; x = _rank[x] , y = _rank[y]; if(x>y){int t=x;x=y,y=t;} // cout<<x<<" "<<y<<" "<<RMQ(x+1,y)<<" "; return RMQ(x+1,y); } void solve(int &mxTime , int &ansl , int &ansLf) { ansl = ansLf = mxTime = 0; for(int l=1 ; l<=n/2 ; l++) {//最外层循环节长度 for(int i=0 ; i+l<n ; i+=l){ int mxl = RMQPOS(i , i+l); int time = mxl/l+1; int del = time*l-mxl , curpos=i , mxRank=_rank[i]; int t; for(t=1 ; t<l ; t++){ if(i<t || s[i-t]!=s[i+l-t]) break; if(_rank[i-t]<mxRank){ mxRank = _rank[i-t]; curpos = i-t; } if(t==del){ mxRank = _rank[i-t]; curpos = i-t , time++; } } if(mxTime<time||(mxTime==time&&mxRank<_rank[ansLf])) mxTime=time,ansl=time*l,ansLf=curpos; } } } int main() { //freopen("a.in" , "r" , stdin); int cas =0 ; while(scanf("%s" , s)) { n = strlen(s); if(n==1 && s[0]=='#') break; printf("Case %d: ",++cas); for(int i=0 ; i<n ; i++) r[i] = s[i]-'a'+1; r =0; da(r,sa,n+1,27); callHeight(r,sa,n); ST(); int mxTime , ansl , ansLf; solve(mxTime , ansl , ansLf); if(mxTime==1){ char minc='a'; for(int i=0 ; i<n ; i++){ minc=min(minc , s[i]); } printf("%c\n" , minc); continue; } for(int i=0 , j=ansLf ; i<ansl ; i++,j++) printf("%c" , s[j]); puts(""); } return 0; }
相关文章推荐
- 一行代码搞定所有屏幕适配AbViewUtil
- 自建pyspider中的mysql语句
- My First Web Server
- java编译脚本的进阶之路
- 进击python第4篇:初探模块
- 我是如何入门Android的
- Android AutoLayout全新的适配方式 堪称适配终结者
- 安装RPM包或源码包
- SQL Server截取字符串和处理中文技巧
- 使用cocoadPod updating local specs repositories 卡主
- 在Linux上搭建samba服务后,到Windos上访问不了共享目录的问题排障
- 代码等式[POI]
- 78.Bulls and Cows
- 学习笔记---蚂蚁感冒
- 在Linux上搭建samba服务后,到Windos上访问不了共享目录的问题排障
- 拼接HTML代码在UIWebVIew中显示
- 浅谈字符串处理函数(二)
- CString和CByteArray的相互转化
- HMM学习笔记_1(从一个实例中学习DTW算法)
- POJ 1094(拓扑排序)