题意:
对于给出的字符串S, 长度不超过1000,
求其中本质不同的子串的数量, 这些子串满足在字符串S中出现了至少不重合的2次
题解:
将串放入后缀自动机中然后求出每一个节点对应的子串为后缀的子串出现的最早和最晚的位置
然后根据
//return len[last] - len[fail[last]];//多添加一个子串所产生不同子串的个数然后根据这个改一下
if (R[i] - L[i] > len[fail[i]]) ans += min(len[i], R[i] - L[i]) - len[fail[i]];
1 #include <set> 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include <string> 9 #include 10 #include 11 #include 12 #include 13 #include 14 15 #define pi acos(-1.0) 16 #define eps 1e-9 17 #define fi first 18 #define se second 19 #define rtl rt<<1 20 #define rtr rt<<1|1 21 #define bug printf("******\n") 22 #define mem(a, b) memset(a,b,sizeof(a)) 23 #define name2str(x) #x 24 #define fuck(x) cout<<#x" = "< 25 #define sfi(a) scanf("%d", &a) 26 #define sffi(a, b) scanf("%d %d", &a, &b) 27 #define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c) 28 #define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d) 29 #define sfL(a) scanf("%lld", &a) 30 #define sffL(a, b) scanf("%lld %lld", &a, &b) 31 #define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c) 32 #define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d) 33 #define sfs(a) scanf("%s", a) 34 #define sffs(a, b) scanf("%s %s", a, b) 35 #define sfffs(a, b, c) scanf("%s %s %s", a, b, c) 36 #define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d) 37 #define FIN freopen("../in.txt","r",stdin) 38 #define gcd(a, b) __gcd(a,b) 39 #define lowbit(x) x&-x 40 #define IO iOS::sync_with_stdio(false) 41 42 43 using namespace std; 44 typedef long long LL; 45 typedef unsigned long long ULL; 46 const ULL seed = 13331; 47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; 48 const int maxn = 1e4 + 50; 49 const int maxm = 8e6 + 10; 50 const int INF = 0x3f3f3f3f; 51 const int mod = 1e9 + 7; 52 53 struct Suffix_Automaton { 54 int last, tot, nxt[maxn << 1][26], fail[maxn << 1];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号 55 int len[maxn << 1];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]]) 56 LL num[maxn << 1];// 该状态子串的数量 57 LL maxx[maxn << 1];// 长度为x的子串出现次数最多的子串的数目 58 LL sum[maxn << 1];// 该节点后面所形成的自字符串的总数 59 LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度 60 int X[maxn << 1], Y[maxn << 1]; // Y表示排名为x的节点,X表示该长度前面还有多少个 61 int L[maxn << 1], R[maxn << 1];//L表示对应节点代表的数组的最早出现位置,R表示最晚出现位置 62 63 void init() { 64 tot = last = 1; 65 fail[1] = len[1] = 0; 66 for (int i = 0; i <= 25; i++) nxt[1][i] = 0; 67 68 } 69 70 void extend(int c) { 71 int u = ++tot, v = last; 72 for (int i = 0; i <= 25; i++) nxt[u][i] = 0; 73 fail[u] = 0; 74 L[u] = R[u] = len[u] = len[v] + 1; 75 num[u] = 1; 76 for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u; 77 if (!v) fail[u] = 1; 78 else if (len[nxt[v][c]] == len[v] + 1) fail[u] = nxt[v][c]; 79 else { 80 int now = ++tot, cur = nxt[v][c]; 81 len[now] = len[v] + 1; 82 memcpy(nxt[now], nxt[cur], sizeof(nxt[cur])); 83 fail[now] = fail[cur]; 84 fail[cur] = fail[u] = now; 85 L[now] = L[cur], R[now] = R[cur]; 86 for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now; 87 } 88 last = u; 89 //return len[last] - len[fail[last]]; 90 } 91 92 93 void get_sa() { // Y表示排名为x的节点,X表示该长度前面还有多少个 94 for (int i = 0; i <= tot; i++) X[i] = 0; 95 for (int i = 1; i <= tot; i++) X[len[i]]++; 96 for (int i = 1; i <= tot; i++) X[i] += X[i - 1]; 97 for (int i = 1; i <= tot; i++) Y[X[len[i]]--] = i; 98 } 99 100 int get_L_R() { 101 int ans = 0; 102 for (int i = tot; i; i--) { 103 L[fail[Y[i]]] = min(L[fail[Y[i]]], L[Y[i]]); 104 R[fail[Y[i]]] = max(R[fail[Y[i]]], R[Y[i]]); 105 } 106 for (int i = 1; i <= tot; i++)//不相交且出现次数至少2的子串个数 107 if (R[i] - L[i] > len[fail[i]]) ans += min(len[i], R[i] - L[i]) - len[fail[i]]; 108 return ans; 109 } 110 } sam; 111 112 char s[maxn]; 113 114 int main() { 115 #ifndef ONLINE_JUDGE 116 FIN; 117 #endif 118 while (~sfs(s)) { 119 if (s[0] == '#') break; 120 sam.init(); 121 int len = strlen(s); 122 for (int i = 0; i < len; ++i) sam.extend((s[i] - 'a')); 123 sam.get_sa(); 124 printf("%d\n", sam.get_L_R()); 125 } 126 #ifndef ONLINE_JUDGE 127 cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl; 128 #endif 129 return 0; 130 }