1. 程式人生 > >【後綴數組】【RMQ】HDU 6194 - string string string (2017ICPC沈陽網絡賽)

【後綴數組】【RMQ】HDU 6194 - string string string (2017ICPC沈陽網絡賽)

namespace 記得 initial acmer panel tom 技術 one ack

string string string

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Problem Description Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k
times as an important string, and you need to find out how many substrings which are important strings. Input The first line contains an integer T (T100) implying the number of test cases.
For each test case, there are two lines:
the first line contains an integer k (k1) which is described above;
the second line contain a string s
(length(s)105).
It‘s guaranteed that length(s)2?106.

length(s)2?106 Output For each test case, print the number of the important substrings in a line. Sample Input 2 2 abcabc 3 abcabcabcabc

Sample Output 6 9

Solution

題意:給一個串,問你其中正好出現k次的子串有多少個

思路:求出給的串的後綴數組和height數組,然後對於height數組中一個長度k-1的區間,如果兩邊的值比區間內的最小值(可以RMQ進行O(1)的查詢)都要小,那這段區間就是對答案有貢獻的。註意k=1時需要特殊處理一下,此時就是後綴數組派上用場的時候了。有不少細節在裏面,具體請看代碼。還有一個坑到哭泣的地方:由於是多組數據,一定要記得每次清空height數組

(不清空的話如果這次的字符串比上一次的短,訪問height[n+1]時預期的是0,但實際上是上次字符串的height值),否則要找十年才知道WA在哪。

技術分享

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define MAXN 101111
  4 using namespace std;
  5 char s[MAXN];
  6 int t1[MAXN],t2[MAXN],cc[MAXN],sa[MAXN],rnk[MAXN],height[MAXN];
  7 int len;
  8 bool cmp(int *y,int a,int b,int k)
  9 {
 10     int a1=y[a];
 11     int b1=y[b];
 12     int a2=a+k>=len ? -1:y[a+k];
 13     int b2=b+k>=len ? -1:y[b+k];
 14     return a1==b1 && a2==b2;
 15 }
 16 int make_sa()
 17 {
 18     int *x=t1,*y=t2;
 19     int m=30;
 20     for(int i=0; i<m; i++) cc[i]=0;
 21     for(int i=0; i<len; i++) ++cc[x[i]=s[i]-a];
 22     for(int i=1; i<m; i++) cc[i]+=cc[i-1];
 23     for(int i=len-1; i>=0; i--) sa[--cc[x[i]]]=i;
 24 
 25     for(int k=1; k<=len; k<<=1)
 26     {
 27         int p=0;
 28         for(int i=len-k; i<len; i++) y[p++]=i;
 29         for(int i=0; i<len; i++)
 30            if( sa[i]>=k ) y[p++]=sa[i]-k;
 31 
 32         for(int i=0; i<m; i++) cc[i]=0;
 33         for(int i=0; i<len; i++) ++cc[x[y[i]]];
 34         for(int i=1; i<m; i++) cc[i]+=cc[i-1];
 35         for(int i=len-1; i>=0; i--) sa[--cc[x[y[i]]]]=y[i];
 36 
 37         swap(x,y);
 38         m=1; x[sa[0]]=0;
 39         for(int i=1; i<len; i++)
 40           x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++;
 41 
 42         if( m>=len ) break;
 43     }
 44 }
 45 void make_height()
 46 {
 47     for(int i=0; i<len; i++) rnk[sa[i]]=i;
 48     height[0]=0;
 49     int k=0;
 50     for(int i=0; i<len; i++)
 51     {
 52         if(!rnk[i]) continue;
 53         int j=sa[rnk[i]-1];
 54         if(k) k--;
 55         while(s[i+k]==s[j+k]) k++;
 56         height[rnk[i]]=k;
 57     }
 58 }
 59 
 60 
 61 int n,minl[100022][18];
 62 
 63 void S_table(){
 64     int l = log(len) / log(2);
 65     for(int j = 1;j <= l;++j){
 66         for(int i = 1;i + (1 << (j - 1)) - 1 <= len;++i){
 67             minl[i][j] = min(minl[i][j-1],minl[i+(1<<(j-1))][j-1]);
 68         }
 69     }
 70 }
 71 
 72 int rmq(int l,int r){
 73     int k = log(r-l+1) / log(2);
 74     return min(minl[l][k],minl[r-(1<<k)+1][k]);
 75 }
 76 
 77 
 78 int T,k,cnt[30];
 79 
 80 int main(){
 81     cin >> T;
 82     while(T--){
 83         int ans = 0;
 84         memset(height,0,sizeof height);    /**< !!! */
 85         scanf("%d",&k);
 86         scanf("%s",s); len = strlen(s);
 87         make_sa();
 88         make_height();
 89         n = len - 1;
 90         for(int i = 0;i < 100022;++i) minl[i][0] = 1e9;
 91         for(int i = 1;i <= len;++i)
 92             minl[i][0] = height[i];
 93         S_table();
 94 
 95 
 96         if(k == 1){
 97             for(int i = 1;i <= n+1;++i){
 98                 int tmp = len - sa[i-1];
 99                 if(height[i-1] < tmp && height[i] < tmp)
100                     ans += tmp - max(height[i-1],height[i]);
101             }
102             printf("%d\n",ans);
103             continue;
104         }
105 
106         for(int i = 1;i <= n - k + 2;++i){
107             int tmp = rmq(i,i+k-2);
108             if(height[i-1] < tmp && height[i+k-1] < tmp)
109                 ans += tmp - max(height[i-1],height[i+k-1]);
110         }
111 
112         printf("%d\n",ans);
113     }
114 }

【後綴數組】【RMQ】HDU 6194 - string string string (2017ICPC沈陽網絡賽)