HDU2459 后缀数组+RMQ

题目大意:

在原串中找到一个拥有连续相同子串最多的那个子串

比如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值小的开头的字符串

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <vector>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <iostream>
  7 using namespace std;
  8 typedef long long ll;
  9 const int N = 100010;
 10 int r[N] , sa[N] , _rank[N] , height[N];
 11 int wa[N] , wb[N] , wv[N] , wsf[N];
 12 int cmp(int *r , int a , int b , int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
 13 void da(int *r , int *sa , int n , int m)
 14 {
 15     int i,j,p,*x=wa,*y=wb,*t;
 16     for(i=0;i<m;i++)wsf[i]=0;
 17     for(i=0;i<n;i++)wsf[x[i]=r[i]]++;
 18     for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
 19     for(i=n-1;i>=0;i--) sa[--wsf[x[i]]]=i;
 20     for(j=1,p=1;p<n;j*=2,m=p){
 21         for(p=0,i=n-j;i<n;i++) y[p++]=i;
 22         for(i=0;i<n;i++) if(sa[i]>=j)y[p++]=sa[i]-j;
 23         for(i=0;i<n;i++) wv[i]=x[y[i]];
 24         for(i=0;i<m;i++) wsf[i]=0;
 25         for(i=0;i<n;i++) wsf[wv[i]]++;
 26         for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
 27         for(i=n-1;i>=0;i--) sa[--wsf[wv[i]]]=y[i];
 28         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
 29             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
 30     }
 31     return;
 32 }
 33 void callHeight(int *r , int *sa , int n)
 34 {
 35     int i,j,k=0;
 36     for(i=1;i<=n;i++) _rank[sa[i]]=i;
 37     for(i=0;i<n;height[_rank[i++]]=k)
 38         for(k?k--:0,j=sa[_rank[i]-1];r[i+k]==r[j+k];k++);
 39     return;
 40 }
 41
 42 int dp[N<<1][18] , n;
 43 char s[N];
 44 void ST()
 45 {
 46     memset(dp , 0x3f , sizeof(dp));
 47     for(int i=1 ; i<=n ; i++)dp[i][0]=height[i];
 48     for(int k=1 ; (1<<k)<=n ; k++){
 49         for(int i=1 ; i<=n ; i++){
 50             dp[i][k] = min(dp[i][k-1] , dp[i+(1<<(k-1))][k-1]);
 51         }
 52     }
 53 }
 54 int RMQ(int s , int t)
 55 {
 56     int d = t-s+1;
 57     int k = (int)log2(d*1.0);
 58    // cout<<s<<" "<<t<<" "<<k<<" "<<t-(1<<k)+1<<endl;
 59     return min(dp[s][k] , dp[t-(1<<k)+1][k]);
 60 }
 61 int RMQPOS(int x , int y)
 62 {
 63   //  cout<<"cal pos: "<<x<<" "<<y<<" ";
 64     x = _rank[x] , y = _rank[y];
 65     if(x>y){int t=x;x=y,y=t;}
 66    // cout<<x<<" "<<y<<" "<<RMQ(x+1,y)<<" ";
 67     return RMQ(x+1,y);
 68 }
 69 void solve(int &mxTime , int &ansl , int &ansLf)
 70 {
 71     ansl = ansLf = mxTime = 0;
 72     for(int l=1 ; l<=n/2 ; l++) {//最外层循环节长度
 73         for(int i=0 ; i+l<n ; i+=l){
 74             int mxl = RMQPOS(i , i+l);
 75             int time = mxl/l+1;
 76
 77             int del = time*l-mxl , curpos=i , mxRank=_rank[i];
 78             int t;
 79             for(t=1 ; t<l ; t++){
 80                 if(i<t || s[i-t]!=s[i+l-t]) break;
 81                 if(_rank[i-t]<mxRank){
 82                     mxRank = _rank[i-t];
 83                     curpos = i-t;
 84                 }
 85                 if(t==del){
 86                     mxRank = _rank[i-t];
 87                     curpos = i-t , time++;
 88                 }
 89             }
 90
 91             if(mxTime<time||(mxTime==time&&mxRank<_rank[ansLf])) mxTime=time,ansl=time*l,ansLf=curpos;
 92
 93         }
 94     }
 95 }
 96 int main()
 97 {
 98     //freopen("a.in"  , "r" , stdin);
 99     int cas =0 ;
100     while(scanf("%s" , s))
101     {
102         n = strlen(s);
103         if(n==1 && s[0]==‘#‘) break;
104         printf("Case %d: ",++cas);
105         for(int i=0 ; i<n ; i++) r[i] = s[i]-‘a‘+1;
106         r[n]=0;
107         da(r,sa,n+1,27);
108         callHeight(r,sa,n);
109         ST();
110
111         int mxTime , ansl , ansLf;
112         solve(mxTime , ansl , ansLf);
113         if(mxTime==1){
114             char minc=‘a‘;
115             for(int i=0 ; i<n ; i++){
116                 minc=min(minc , s[i]);
117             }
118             printf("%c\n" , minc);
119             continue;
120         }
121         for(int i=0 , j=ansLf ; i<ansl ; i++,j++) printf("%c" , s[j]);
122         puts("");
123     }
124     return 0;
125 }
时间: 2024-08-15 11:06:06

HDU2459 后缀数组+RMQ的相关文章

【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=1770 题解:一开始理解错题意,以为是abcxxxcba(xxx为v),开心地打了后缀数组后发现哎样例不对丫.. UVA的意思是abcxxxabc(xxx为v). 类似poj3693,我们暴

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

HDU_6194 后缀数组+RMQ

好绝望的..想了五个多小时,最后还是没A...赛后看了下后缀数组瞬间就有了思路...不过因为太菜,想了将近两个小时才吧这个题干掉. 首先,应当认为,后缀数组的定义是,某字符串S的所有后缀按照字典序有小到大的顺序排列(使用下标表示后缀).因为具体过程没太看懂,但是参见刘汝佳蓝书<算法竞赛黑暗圣典>可以得到一个聪明的NLOGN的神器算法.不过这个不太重要. 之后还可以通过他在LCP问题中提到的RANK,height数组相关算法,处理出来height数组,之后其他的可以扔掉. <黑暗圣典>

Codeforces Round #422 (Div. 2) E. Liar 后缀数组+RMQ+DP

E. Liar The first semester ended. You know, after the end of the first semester the holidays begin. On holidays Noora decided to return to Vi?kopolis. As a modest souvenir for Leha, she brought a sausage of length m from Pavlopolis. Everyone knows th

SPOJ687---REPEATS - Repeats(后缀数组+RMQ)

A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed string t with length l>=1. For example, the string s = abaabaabaaba is a (4,3)-repeat with t = aba as its seed string. That is, the seed string t is 3 charac

POJ 3693 后缀数组+RMQ

点击打开链接 题意:问连续重复部分最多的串是什么,不能重叠,且我们要字典序最小的串如xbcabcab,有bcabca重复次数为2,cabcab重复次数也为2,那么要前边那个 思路:以前写过一个类似的,SPOJ 687,这个只是求连续重复部分最多的串的次数,并不需要将按字典序最小串输出,那么我们可以用到SPOJ687的代码,用它我们可以求出那个重复的次数和满足这个次数的串的长度,那么就只差找到字典序最小的那个串了,而我们知道后缀数组的sa数组就是按字典序来的嘛,从字典序最小开始找,找到就跳出,输出

uva 12338 - Anti-Rhyme Pairs(后缀数组+RMQ)

题目链接:uva 12338 - Anti-Rhyme Pairs 题目大意:给定若干个字符串,每次询问两个字符串的最长公共前缀. 解题思路:本来应该将每个字符串连接起来做后缀数组,但其实可以直接把一个字符串看成是一个字符,然后排序了就对应是SA数组,然后处理height即可.然后根据后缀数组的性质,字符串i和j的最长公共前缀长度即为rank[i]+1~rank[j]之间height的最小值.特判i=j的情况. #include <cstdio> #include <cstring>

【poj3693】Maximum repetition substring(后缀数组+RMQ)

自己看着大牛的论文学了一下后缀数组,看了好久好久,想了好久好久才懂了一点点皮毛TAT 然后就去刷传说中的后缀数组神题,poj3693是进化版的,需要那个相同情况下字典序最小,搞这个搞了超久的说. 先简单说一下后缀数组.首先有几个重要的数组: ·SA数组(后缀数组):保存所有后缀排序后从小到大的序列.[即SA[i]=j表示排名第i的后缀编号为j]        ·rank数组(名次数组):记录后缀的名次.[即rank[i]=j表示编号为i的后缀排名第j] 用倍增算法可以在O(nlogn)时间内得出

ZOJ1905Power Strings (KMP||后缀数组+RMQ求循环节)

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defin