洛谷P4070 生成魔咒
题意:给定字符串,求每个前缀的本质不同的子串数量。字符集1e9。
解:在线构造后缀自动机并统计答案。
答案就是∑len[i] - len[fail[i]]
每次增加的时候,至多对三个节点有影响。然而把Q分裂为nQ本质不同的子串数没变。
于是增加的只有len[np] - len[fail[np]]
map维护转移边。
1 #include <cstdio> 2 #include <map> 3 4 typedef long long LL; 5 const int N = 200010; 6 7 int len[N], fail[N], last, top; 8 LL ans; 9 std::map<int, int> mp[N]; 10 11 inline void init() { 12 top = last = 1; 13 return; 14 } 15 16 inline void insert(int f) { 17 int p = last, np = ++top; 18 last = np; 19 len[np] = len[p] + 1; 20 while(p && !mp[p].count(f)) { 21 mp[p][f] = np; 22 p = fail[p]; 23 } 24 //printf("p = %d \n", p); 25 if(!p) { 26 fail[np] = 1; 27 ans += len[np]; 28 //printf("1 : ans += %d \n", len[np]); 29 } 30 else { 31 int Q = mp[p][f]; 32 //printf("Q = %d \n", Q); 33 if(len[Q] == len[p] + 1) { 34 fail[np] = Q; 35 ans += len[np] - len[Q]; 36 //printf("2 : ans += %d \n", len[np] - len[Q]); 37 } 38 else { 39 int nQ = ++top; 40 len[nQ] = len[p] + 1; 41 fail[nQ] = fail[Q]; 42 fail[Q] = fail[np] = nQ; 43 mp[nQ] = mp[Q]; 44 while(mp[p].count(f) && mp[p][f] == Q) { 45 mp[p][f] = nQ; 46 p = fail[p]; 47 } 48 ans += len[np] - len[nQ]; 49 } 50 } 51 return; 52 } 53 54 int main() { 55 int n; 56 scanf("%d", &n); 57 init(); 58 for(int i = 1, x; i <= n; i++) { 59 scanf("%d", &x); 60 insert(x); 61 printf("%lld\n", ans); 62 } 63 64 return 0; 65 }