【藍橋杯】算法提高 着急的WYF(不同子串個數)

算法提高 着急的WYF

問題描述
WYF在戰網上的密碼非常複雜(含大小寫字母、數字以及特殊字符,如”!”,”@”,”{”等),但他很不巧地忘記了。現在他非常着急,都快飛起來了。他只記得他的密碼是某個字符串S的子串。現在問題來了,你要告訴他有多少種可能的密碼,以幫助他確定能在多少時間內完成枚舉並嘗試解密工作。

輸入格式
輸入僅包含一行,爲一個字符串S,不含空格。

輸出格式
輸出一個整數,表示可能的密碼數量。

樣例輸入
ToTal

樣例輸出
14

數據規模和約定
對於70%的數據,S的長度不超過1000;(暴力)
對於100%的數據,S的長度不超過15000。(Suffix Array)



—— 分割線 ——



分析:
題目已經給了提示,想要過所有的測試數據,必須要用到Suffix Array(後綴數組)。
由於之前我已經詳細地講解了關於後綴數組的相關知識,並介紹了其在求字符串子串個數上的應用,因此這裏我就不多說口水話了,直接上代碼(如果有沒看過那篇文章的同學,我強烈建議先看再做,這是鏈接【算法與數據結構】—— 後綴數組),本題的完整代碼如下:

#include<iostream>
using namespace std;

const int N=15010;
class SuffixArray{
	private:
		static const int MAX=N;
		int wa[MAX],wb[MAX],wd[MAX],r[MAX];			//n表示字符串的長度 
		bool isSame(int *r,int a,int b,int len)
		{ return r[a]==r[b] && r[a+len]==r[b+len]; }
		void da(int n,int m)						 
		{
			int *x=wa,*y=wb,*t;
			for(int i=0;i<m;i++) wd[i]=0;
			for(int i=0;i<n;i++) wd[x[i]=r[i]]++;
			for(int i=1;i<m;i++) wd[i]+=wd[i-1];
			for(int i=n-1;i>=0;i--) sa[--wd[x[i]]]=i;
			for(int j=1,p=1;p<n;j<<1,m=p){
				//對第二關鍵字排序
				p=0;
				for(int i=n-j;i<n;i++) y[p++]=i;
				for(int i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
				//對第一關鍵字排序
				for(int i=0;i<m;i++) wd[i]=0;
				for(int i=0;i<n;i++) wd[x[i]]++;
				for(int i=1;i<m;i++) wd[i]+=wd[i-1];
				for(int i=n-1;i>=0;i--) sa[--wd[x[y[i]]]]=y[i];
				//利用指針操作調換兩數組的內容
				t=x,x=y,y=t;
				//更新x數組 
				p=1,x[sa[0]]=0;
				for(int i=1;i<n;i++) x[sa[i]]=isSame(y,sa[i-1],sa[i],j)?p-1:p++;
			}
		}
	public:
		int sa[MAX],rank[MAX],height[MAX],n; 
		void calSuffixArray(char *s)		//計算後綴數組sa 
		{
			n=0;
			while(*s){
				r[n++]=*s-'!'+1;
				s++;
			}
			r[n]=0; 						//對於r數組而言,其還需要在最後加一個0方便處理 
			da(n+1,100);					 
		}
		void calRank()						//計算名次數組rank 
		{  for(int i=1;i<=n;i++) rank[sa[i]]=i;  }
		void calHeight()					//計算相鄰的兩個後綴的最長公共前綴長度數組height 
		{
			int j,k=0;
			calRank();
			for(int i=0;i<n;i++){
				if(k) k--;
				int j=sa[rank[i]-1];
				while(r[i+k]==r[j+k]) k++;
				height[rank[i]]=k;
			}
		}
		long long calSubstringNum(char *s)	//對於某個字符串str,計算其不同子串的個數 
		{
			calSuffixArray(s);
			calHeight();
			long long ans=0;
			for(int i=1;i<=n;i++)
				ans += n - sa[i] -height[i];
			return ans;
		}
};

int main()
{
	char chs[N];
	cin>>chs;
	SuffixArray suffixArray;
	cout<<suffixArray.calSubstringNum(chs)<<endl;
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章