HDU 4029 Distinct Sub-matrix(哈希+后缀数组)

来源:互联网 发布:windows 7库 快捷方式 编辑:程序博客网 时间:2024/05/22 16:05

题意:给出一个矩阵(n,m<=128),求出这个矩阵不同的子矩阵的数量。

思路:首先容易想到对这个矩阵的每一个子矩阵进行哈希然后找出不重复的,但是这样做光是枚举所有矩阵复杂度就会达到O(n^4),更不用说空间复杂度无法承受了。

考虑类似于求矩阵最大子矩阵和的方法,将原矩阵的每一列的任意子序列哈希,即用hash[i][j][k]表示原矩阵第i列从第j行到第k行的哈希值。

有了这个以后我们可以枚举子矩阵的行数h,然后对于所有h行的子矩阵我们将哈希值离散化然后插入到后缀数组中,注意不同行的哈希值之间要用一个没出现的数字分隔开,剩下的就是后缀数组求不同的子串数量。

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<vector>#include<map>#include<queue>#include<stack>#include<string>#include<map>#include<set>#include<ctime>#define eps 1e-6#define LL long long#define ULL unsigned long long#define pii pair<int, int>//#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int MAXN = 150; const ULL base = 131;int n, m;ULL Hash[MAXN][MAXN][MAXN];ULL G[MAXN][MAXN];struct SuffixArray {      int s[MAXN*MAXN];      /// 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)      int sa[MAXN*MAXN];     // 后缀数组,sa[0]一定是n-1,即最后一个字符      int rank[MAXN*MAXN];   // 名次数组      int height[MAXN*MAXN]; // height数组      int t[MAXN*MAXN], t2[MAXN*MAXN], c[MAXN*MAXN]; // 辅助数组      int n; // 字符个数        void clear() { n = 0; memset(sa, 0, sizeof(sa)); }        /// m为最大字符值加1。!!! 调用之前需设置好s和n      void build_sa(int m) {       int i, *x = t, *y = t2;      for(i = 0; i < m; i++) c[i] = 0;      for(i = 0; i < n; i++) c[x[i] = s[i]]++;      for(i = 1; i < m; i++) c[i] += c[i-1];      for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;      for(int k = 1; k <= n; k <<= 1) {        int p = 0;        for(i = n-k; i < n; i++) y[p++] = i;        for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;        for(i = 0; i < m; i++) c[i] = 0;        for(i = 0; i < n; i++) c[x[y[i]]]++;        for(i = 0; i < m; i++) c[i] += c[i-1];        for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];        swap(x, y);        p = 1; x[sa[0]] = 0;        for(i = 1; i < n; i++)        x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k] ? p-1 : p++;        if(p >= n) break;        m = p;      }    }      void build_height() {      int i, j, k = 0;      for(i = 0; i < n; i++) rank[sa[i]] = i;      for(i = 0; i < n; i++) {          if(k) k--;    j = sa[rank[i]-1];      while(s[i+k] == s[j+k]) k++;      height[rank[i]] = k;      }    }  } sa;int pos[MAXN*MAXN];void addchar(int x, int p) {pos[sa.n] = p;sa.s[sa.n++] = x;}map<ULL, int> lsh;int tot;int ls(ULL x) {if(lsh[x]) return lsh[x];return lsh[x] = ++tot;}int main() {    //freopen("input.txt", "r", stdin);int T; cin >> T;int kase = 0;while(T--) {cin >> n >> m;for(int i = 1; i <= n; i++) {char tmp[MAXN];scanf("%s", tmp);for(int j = 1; j <= m; j++) G[i][j] = tmp[j-1] - 'A' + 1; }for(int i = 1; i <= m; i++) {for(int j = 1; j <= n; j++) {for(int k = j; k <= n; k++) {Hash[i][j][k] = Hash[i][j][k-1] * base + G[k][i];}}}LL ans = 0;for(int h = 1; h <= n; h++) {sa.clear();lsh.clear();tot = 0;int shit = n * m + 1;for(int i = 1; i+h-1 <= n; i++) {for(int j = 1; j <= m; j++) {addchar(ls(Hash[j][i][i+h-1]), j);}addchar(++shit, 0);}addchar(0, 0);sa.build_sa(shit+10);sa.build_height();for(int i = 1; i < sa.n; i++) if(pos[sa.sa[i]]) {ans += m - pos[sa.sa[i]] + 1 - sa.height[i];}}printf("Case #%d: ", ++kase);cout << ans << endl;}    return 0;}

0 0
原创粉丝点击