F - New Distinct Substrings (后缀数组)

题目链接:https://cn.vjudge.net/contest/283743#problem/F

题目大意:给你一个字符串,然后让你求出不同的子串的个数。

具体思路:首先,一个字符串中总的子串个数是len*(len+1)/2,然后就开始去重了,通过height数组,求出所有重复的子串的个数,然后就用总的子串的个数-重复的子串的个数就可以了。

AC代码:

 1 #include<iostream>
 2 #include<stack>
 3 #include<cstring>
 4 #include<iomanip>
 5 #include<stdio.h>
 6 #include<algorithm>
 7 #include<cmath>
 8 using namespace std;
 9 # define ll long long
10 const int maxn = 5e5+100;
11 int cntA[maxn], cntB[maxn], sa[maxn], tsa[maxn], A[maxn], B[maxn], height[maxn];
12 int Rank[maxn];
13 char ch[maxn];
14 ll n;
15 //sa[i]代表第i小的后缀位置,Rank[i]代表第i位置开始的后缀在所有的后缀串中排名第几
16 // height[i]代表排名第i个字符串和第i-1个字符串的相同前缀的长度
17 void cal()
18 {
19     for(int i = 0; i < 256; i++) cntA[i] = 0;
20     for(int i = 1; i <= n; i++) cntA[ch[i-1]]++;
21     for(int i = 1; i < 256; i++) cntA[i] += cntA[i-1];
22     for(int i = n; i; i--) sa[cntA[ch[i-1]]--] = i;
23     Rank[sa[1]] = 1;
24     for(int i = 2; i <= n; i++)
25     {
26         Rank[sa[i]] = Rank[sa[i-1]];
27         if(ch[sa[i]-1] != ch[sa[i-1]-1]) Rank[sa[i]]++;
28     }
29     for(int l = 1; Rank[sa[n]] < n; l <<= 1)
30     {
31         memset(cntA, 0, sizeof(cntA));
32         memset(cntB, 0, sizeof(cntB));
33         for(int i = 1; i <= n; i++)
34         {
35             cntA[A[i] = Rank[i]]++;
36             cntB[B[i] = (i+l <= n)?Rank[i+l]:0]++;
37         }
38         for(int i = 1; i <= n; i++) cntB[i] += cntB[i-1];
39         for(int i = n; i; i--) tsa[cntB[B[i]]--] = i;
40         for(int i = 1; i <= n; i++) cntA[i] += cntA[i-1];
41         for(int i = n; i; i--) sa[cntA[A[tsa[i]]]--] = tsa[i];
42         Rank[sa[1]]=1;
43         for(int i = 2; i <= n; i++)
44         {
45             Rank[sa[i]] = Rank[sa[i-1]];
46             if(A[sa[i]] != A[sa[i-1]] || B[sa[i]] != B[sa[i-1]]) Rank[sa[i]]++;
47         }
48     }
49     for(int i = 1, j = 0; i <= n; i++)
50     {
51         if(j) j--;
52         while(ch[i+j-1] == ch[sa[Rank[i]-1] + j - 1]) j++;
53         height[Rank[i]] = j;
54     }
55 }
56 int main()
57 {
58     int T;
59     scanf("%d",&T);
60     while(T--)
61     {
62         scanf("%s",ch);
63        n=strlen(ch);
64         if(n==1)
65         {
66             printf("1\n");
67             continue;
68         }
69         // cout<<1<<endl;
70         cal();
71         ll ans=n*(n+1)/2;
72         //cout<<ans<<endl;
73         for(int i=2; i<=n; i++)
74         {
75             ans-=height[i];
76          // cout<<i<<" "<<height[i]<<endl;
77         }
78         printf("%lld\n",ans);
79     }
80     return 0;
81 }

猜你喜欢

转载自www.cnblogs.com/letlifestop/p/10387024.html