轉載請註明出處,謝謝http://blog.csdn.net/acm_cxlove/article/details/7854526
by---cxlove
題目:給出一個字母矩陣,求出有多少個不相同的子矩陣
http://acm.hdu.edu.cn/showproblem.php?pid=4029
嘛,似乎可以暴力的
首先枚舉寬度,然後對每一個寬度進行HASH,hash[i][j]表示第i行,從第j個字元開始的w個字元的HASH值。
然後把起點相同的列,連在一起,也就 是豎著把每一列連在一起,列與列之間用一個特殊字元隔開,變成了一個串
剩下的就是求這個串有多少個不同的子串。
可以求出總共有多少個子串,然後利用尾碼數組,通過height數組可以求出有多少個重複的子串,減去即可。
糾結的問題是如何HASH,真是弱爆了。其實我不知道字串HASH,不需要管溢出
每一位設一個權值,原本以為可能衝突會比較嚴重,還準備多重HASH,結果把權值設為26也一次就過了。。。
HASH值範圍大,而且可能有負的,所以離散化一下,map隨便搞搞吧
之後就是求出尾碼數組,這裡debug半天,果斷還是對模板不理解,哭~~~不過過了範例之後還是順利的1Y
#include<iostream>#include<cstdio>#include<map>#include<cstring>#include<cmath>#include<vector>#include<queue>#include<algorithm>#include<set>#define inf (1ull<<63)-1#define N 130#define maxn 100005#define Min(a,b) ((a)<(b)?(a):(b))#define Max(a,b) ((a)>(b)?(a):(b))#define pb(a) push_back(a)#define mem(a,b) memset(a,b,sizeof(a))#define eps 1e-9#define zero(a) fabs(a)<eps#define ULL unsigned long long#define lson (step<<1)#define rson (step<<1|1)#define MOD 1000000007#define mp(a,b) make_pair(a,b)using namespace std;const ULL hash1=26;struct HASH{ULL h1;HASH(){}HASH(ULL _h1):h1(_h1){}}h[N][N];//以下為倍增演算法求尾碼數組 int wa[maxn],wb[maxn],wv[maxn],Ws[maxn]; int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];} void da(const int *r,int *sa,int n,int m){ int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) Ws[i]=0; for(i=0;i<n;i++) Ws[x[i]=r[i]]++; for(i=1;i<m;i++) Ws[i]+=Ws[i-1]; for(i=n-1;i>=0;i--) sa[--Ws[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++) Ws[i]=0; for(i=0;i<n;i++) Ws[wv[i]]++; for(i=1;i<m;i++) Ws[i]+=Ws[i-1]; for(i=n-1;i>=0;i--) sa[--Ws[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; } int sa[maxn],Rank[maxn],height[maxn]; //求height數組 void calheight(const 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 tot,r[maxn],cnt;char str[N][N];int main(){int t,cas=0,n,m;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);for(int i=0;i<n;i++) scanf("%s",str[i]);mem(h,0);ULL ans=0;for(int w=1;w<=m;w++){tot=1;cnt=0;map<ULL,int> map;map.clear();for(int i=0;i<n;i++){for(int j=0;j+w-1<m;j++){h[i][j].h1=h[i][j].h1*hash1+str[i][j+w-1]-'A';if(map.find(h[i][j].h1)==map.end())map.insert(mp(h[i][j].h1,tot++));}}for(int j=0;j+w-1<m;j++){for(int i=0;i<n;i++){r[cnt++]=map[h[i][j].h1];}r[cnt++]=tot++;}r[cnt]=0;da(r,sa,cnt+1,tot);calheight(r,sa,cnt);ULL tmp=(n*(n+1)/2)*(m-w+1);for(int i=1;i<=cnt;i++){tmp-=height[i];}ans+=tmp;}printf("Case #%d: %I64u\n",++cas,ans);}return 0;}