SA

hdu 4029

题意:给你一个字符矩阵,统计不同的子矩阵的个数;

分析:枚举子矩阵的宽度w,对于每一个w,将每一行长度可以是w的字符串HASH成一个值,然后用map标记,因为宽确定了,hash完之后,然后如果相等就表示此时长度为w的字串

相等,将他们按照每一列排序形成一个字符串,此时如果莫两个长度为x的子串相等就表示此时x*w的子矩阵相同,

这样就是统计m个字符串的不同的子串的个数,这个是SA的论文题;n^3*logn 

HASH会冲突,SEED选择很重要,当然也可以用2个SEED,这样冲突的概率就很小很小了;

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<cstdlib>
  7 #include<map>
  8 #define mk make_pair
  9 
 10 using namespace std;
 11 typedef unsigned long long  ULL;
 12 typedef pair<ULL,ULL> pUU;
 13 const int N = 50000+10;
 14 const int M = 200+10;
 15 const int SEED[2]= {13,11};
 16 char s[M][M];
 17 ULL hash[2][M][M],X[2][M];
 18 int n,m;
 19 map<pUU,int> mp;
 20 int str[N];
 21 struct Suffix_Array {
 22     int a1[N],a2[N],c[N],sa[N],SA[N],*x,*y,n,m;
 23     int height[N],*rank;
 24     void sort(){
 25         for (int i = 0; i < m; i++) c[i] = 0;
 26         for (int i = 0; i < n; i++) c[ x[i] ] ++;
 27         for (int i = 0; i < m; i++) c[i+1] += c[i];
 28         for (int i = n-1; i >= 0; i--) SA[ --c[x[sa[i]]] ] = sa[i];
 29     }
 30     void build_SA(int s[],int _n,int _m) {
 31         n = _n; m = _m;
 32         x = a1; y = a2; x[n] = y[n] = -1;
 33         for (int i = 0; i < n; i++) x[i] = s[i], sa[i] = i;
 34         sort();
 35         for (int k = 1; k <= n; k <<= 1) {
 36             int p = 0;
 37             for (int i = n-k; i < n; i++) sa[ p++ ] = i;
 38             for (int i = 0; i < n; i++) if (SA[i] >= k) sa[ p++ ] =  SA[i] - k;
 39             sort();
 40             p = 0; y[SA[0]] = 0;
 41             for (int i = 1; i < n; i++) {
 42                 if ( x[SA[i-1]] != x[SA[i]] || x[SA[i-1]+k] != x[SA[i]+k] ) p++;
 43                 y[SA[i]] = p;
 44             }
 45             swap(x,y);
 46             if (p+1 == n) break;
 47             m = p + 1;
 48         }
 49         rank = x; getHeight(s);
 50     }
 51     void getHeight(int s[]){
 52         int k = 0;
 53         for (int i = 0; i < n; i++) {
 54             if (k) k--;
 55             if (rank[i] == 0) continue;
 56             int j = SA[rank[i] - 1];
 57             while ( s[j+k] && s[i+k] == s[j+k])  k++;
 58             height[ rank[i] ] = k;
 59         }
 60         height[n] = 0;
 61     }
 62     void check(){
 63         for (int i = 0; i < n; i++) cout<<SA[i]<<" "; cout<<endl;
 64         for (int i = 0; i < n; i++) cout<<rank[i]<<" "; cout<<endl;
 65         for (int i = 0; i < n; i++) cout<<height[i]<<" "; cout<<endl;
 66     }
 67 }H;
 68 
 69 void init(){
 70     //    会用到的一定要清空;
 71     for (int k = 0; k < 2; k++)
 72     for (int i = 0; i < n; i++) {
 73         hash[k][i][m] = 0;//会用到,如果不清空会wa;
 74         hash[k][i][m-1] = s[i][m-1] - 'A'; 
 75         for (int j = m-2; j >= 0; j--) {
 76             hash[k][i][j] = hash[k][i][j+1] * SEED[k] + s[i][j] - 'A';
 77         }
 78     }
 79     X[0][0] = X[1][0] = 1;
 80     for (int k = 0; k < 2; k++)
 81     for (int i = 1; i <= m; i++) {
 82         X[k][i] = X[k][i-1] * SEED[k];
 83     }
 84 }
 85 
 86 int idx[N];
 87 int find(int n){
 88     int ret = idx[H.SA[0]];
 89     for (int i = 1; i < n; i++){
 90         ret += idx[H.SA[i]] - H.height[i];
 91     }
 92     return ret;
 93 }
 94 void solve(){
 95     int ret = 0;
 96     int cnt, tot;
 97     for (int w = 1; w <= m; w++) {
 98         cnt = 0, tot = 1;
 99         mp.clear();
100         for (int j = 0; j+w-1 < m; j++){
101             for (int i = 0; i < n; i++) {
102                 ULL tmp1 = hash[0][i][j] - hash[0][i][j+w] * X[0][w];    
103                 ULL tmp2    = hash[1][i][j] - hash[1][i][j+w] * X[1][w];    
104                 
105                 if (mp.find(mk(tmp1,tmp2)) == mp.end()){
106                     mp[mk(tmp1,tmp2)] = tot++;
107                 }    
108                 idx[cnt] = n - i;
109                 str[cnt++] = mp[mk(tmp1,tmp2)];
110             }
111             idx[cnt] = 0;
112             str[cnt++] = tot++;
113         }
114         H.build_SA(str,cnt,tot);
115     //    H.check();
116         ret += find(cnt);
117     }
118     printf("%d\n",ret);
119 
120 }
121 int main(){
122     int T, cas = 0; scanf("%d",&T);
123     while (T--){
124         scanf("%d%d",&n,&m);
125         for (int i = 0; i < n; i++) {
126             scanf("%s",s[i]);
127         }
128         init();
129         printf("Case #%d: ",++cas);
130         solve();
131     }
132     return 0;
133 }
View Code

相关文章:

  • 2022-12-23
  • 2021-05-29
  • 2021-08-14
  • 2021-10-22
  • 2021-12-03
  • 2021-09-20
  • 2021-09-17
  • 2021-08-22
猜你喜欢
  • 2021-12-11
  • 2022-02-10
  • 2022-02-25
  • 2021-12-19
  • 2022-12-23
  • 2022-02-24
  • 2022-12-23
相关资源
相似解决方案