spoj 405 求不同子串的个数 后缀数组和高度数组的应用
2016-07-30 21:44
453 查看
传送门:spoj 405 求不同子串的个数
因为每个子串都是每个后缀的前缀,那么原问题等价于求所有后缀之间不相同的前缀的个数如果后缀按照sa[1],sa[2]….sa
这样的顺序来计算的,那么不难发现每次增加的子串的个数为n-sa[i]+1,但是其中是有height[i]个和前面字符串的前缀相同的,所以对应于每个sa[i]对整个字符串不同子串的数量贡献
题目大意
求一个字符串不同子串的个数。解题思路
后缀数组和高度数组的应用!因为每个子串都是每个后缀的前缀,那么原问题等价于求所有后缀之间不相同的前缀的个数如果后缀按照sa[1],sa[2]….sa
这样的顺序来计算的,那么不难发现每次增加的子串的个数为n-sa[i]+1,但是其中是有height[i]个和前面字符串的前缀相同的,所以对应于每个sa[i]对整个字符串不同子串的数量贡献
n-sa[i]+1-height[i]所以原问题就转换为了这个公式
n-sa[i]+1-height[i]的累加。
AC代码
#include <cstdio> #include <cstdlib> #include <sstream> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <string> using namespace std; const int maxn = 1111; char s[maxn]; int sa[maxn],t1[maxn],t2[maxn],c[maxn]; int rank[maxn],height[maxn]; void getHeight(int n){ int k = 0; for(int i=1;i<=n;i++)rank[sa[i]] = i; for(int i=0;i<n;i++){ if(k)k--; int j = sa[rank[i]-1]; while(s[i+k]==s[j+k])k++; height[rank[i]] = k; } } bool cmp(int *r,int a,int b,int l){ return (r[a]==r[b] && r[a+l]==r[b+l]); } void build_sa(int m,int n){ int i,*x=t1,*y=t2,k,p; 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(k=1,p=0;p<n;m=p,k<<=1){ 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=1;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]] = cmp(y,sa[i-1],sa[i],k)?p-1:p++; } getHeight(n-1); } int solve(int n){ int ans = n - sa[1]; for(int i=2;i<=n;i++){ ans += n-sa[i]-height[i]; } return ans; } int main(){ int T; cin>>T; while(T--){ scanf("%s",s); int n = strlen(s); build_sa(255,n+1); printf("%d\n",solve(n)); } return 0; }
相关文章推荐
- Cogs 1709. [SPOJ705]不同的子串 后缀数组
- Distinct Substrings SPOJ - DISUBSTR 后缀数组(计算不同的子串数目)
- spoj 694 Distinct Substrings(求不同的子串个数,后缀数组基础题)
- poj2217 后缀数组和高度数组经典应用之找出最长公共子串
- spoj 694. Distinct Substrings 后缀数组求不同子串的个数
- SPOJ 694、705 后缀数组:求不同子串
- SPOJ-694-求字符串中不同子串个数(后缀数组)
- spoj 705 求不同子串的个数(后缀数组)
- SPOJ DISUBSTR - Distinct Substrings(不同子串数量 后缀数组)
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- 后缀数组和高度数组 模板及应用
- SPOJ 694 求不同子串数 后缀数组
- 后缀数组应用5: 求两个不同字串串的最长公共子串
- [spoj DISUBSTR]后缀数组统计不同子串个数
- spoj705 后缀数组求不同子串的个数
- SPOJ(后缀数组求不同子串个数)
- 【后缀数组】【不同子串个数】DISUBSTR spoj694/705
- SPOJ 题目694 Distinct Substrings(后缀数组,求不同的子串个数)
- spoj 220 Relevant Phrases of Annihilation (后缀数组 每个串中都至少出现两次的不重叠最长子串)