我要死了。這是我作過的最噁心的題之一。c++
天下第一的大毒瘤。有gay毒。ide
我不如熊貓好多年...spa
題意:給定字符串,求g[i],表示:[0, i]中知足該子串既是前綴又是後綴還不重疊的子串數。指針
解:題面都寫了KMP,想必跟KMP有關。code
而後我痛苦的思考了1天無果......blog
我首先想到求出nex[]和f[],f[]表示可重疊的既是前綴又是後綴的子串數。繼承
而後想找出f[]和g[]的關係,失敗。字符串
而後想到再來一個len[]表示f[]最長的那一個的長度,仍是不行...get
被折磨了一天,撐不住了,在吃完飯的時候開始看題解。string
發現:咱們要魔改KMP,每次跳完增長以後若大於一半,就再跳...
這時你停住的地方j就是剛好比一半小的最大值。
而後若是i這裏的nex爲0,j顯然爲0,g[]顯然也爲0
不然j不爲0,這時你把f[j - 1]加1就是g[i]
你加的1就是[0, j - 1]這個串。
而後j能夠直接繼承到下一個i
由於你的j和KMP裏的j差很少,除了不超過一半以外都同樣。
而後你i每次 + 1的時候g[]最多 + 1
這樣就搞過了這個大毒瘤題....
(事實上還不是很清楚)
1 #include <cstdio> 2 #include <cstring> 3 4 typedef long long LL; 5 6 const int N = 1000010, MO = 1e9 + 7; 7 8 int nex[N], f[N], g[N]; 9 char s[N]; 10 11 inline void solve() { 12 scanf("%s", s); 13 int n = strlen(s); 14 nex[0] = 0; 15 f[0] = 0; 16 for(int i = 1, j = 0; i < n; i++) { 17 while(j && s[i] != s[j]) { 18 j = nex[j - 1]; 19 } 20 if(s[i] == s[j]) { 21 j++; 22 } 23 nex[i] = j; 24 if(j) { 25 f[i] = f[j - 1] + 1; 26 } 27 else { 28 f[i] = 0; 29 } 30 } 31 32 g[0] = 0; 33 LL ans = 1; 34 for(int i = 1, j = 0; i < n; i++) { 35 while(j && s[i] != s[j]) { 36 j = nex[j - 1]; 37 } 38 if(s[i] == s[j]) { 39 j++; 40 } 41 while(2 * j > (i + 1)) { 42 j = nex[j - 1]; 43 } 44 if(!j) { 45 g[i] = 0; 46 } 47 else { 48 g[i] = f[j - 1] + 1; 49 } 50 ans = (ans * (g[i] + 1)) % MO; 51 } 52 printf("%lld\n", ans); 53 return; 54 } 55 56 int main() { 57 int T; 58 scanf("%d", &T); 59 while(T--) { 60 solve(); 61 } 62 return 0; 63 }
[update]首先有個30分暴力想必你們都會。
說一下SAM作法。你考慮一個border是什麼樣的,顯然前綴是一條鏈,然後綴是該點在fail樹上到根的鏈。因而至關於求這兩個東西的交,還有個深度限制。
給前綴鏈標記爲1,非前綴標記爲0,並統計到根路徑的點權和。這樣,咱們只要找到每一個點在fail樹上知足限制的最深的點,就能知道答案了。
考慮到每一個點在fail樹上向下走的時候,知足限制的最深點也是單調向下的。因而拿一個棧維護當前點到根的鏈,用一個單調指針在棧上找就好了。
1 #include <bits/stdc++.h> 2 3 #define add(x, y) edge[++tp].v = y; edge[tp].nex = e[x]; e[x] = tp 4 5 const int N = 2000010, MO = 1e9 + 7; 6 7 struct Edge { 8 int nex, v; 9 }edge[N]; int tp; 10 11 int n, tr[N][26], fail[N], len[N], e[N], vis[N], Time, val[N], stk[N], top, ans, tot = 1, last = 1; 12 char str[N]; 13 std::queue<int> Q; 14 /* 15 2 16 abcababc 17 abcababc 18 */ 19 namespace bf { 20 typedef unsigned long long uLL; 21 const uLL B = 131; 22 uLL pw[300], h[300]; 23 inline void prework() { 24 pw[0] = 1; 25 for(int i = 1; i <= n; i++) { 26 pw[i] = pw[i - 1] * B; 27 h[i] = h[i - 1] * B + str[i]; 28 } 29 return; 30 } 31 inline uLL Hash(int l, int r) { 32 return h[r] - h[l - 1] * pw[r - l + 1]; 33 } 34 inline void solve() { 35 prework(); 36 int ans = 1; 37 for(int i = 1; i <= n; i++) { 38 /// [1, i] 39 //printf("i = %d \n", i); 40 int temp = 1; 41 for(int t = i >> 1; t; t--) { 42 //printf("t = %d \n", t); 43 if(Hash(1, t) == Hash(i - t + 1, i)) { 44 /// num[i] = t; 45 ++temp; 46 } 47 } 48 ans = 1ll * ans * temp % MO; 49 } 50 printf("%d\n", ans); 51 return; 52 } 53 } 54 55 inline void insert(int f) { 56 int p = last, np = ++tot; 57 last = np; 58 len[np] = len[p] + 1; 59 vis[np] = Time; 60 while(p && !tr[p][f]) { 61 tr[p][f] = np; 62 p = fail[p]; 63 } 64 if(!p) { 65 fail[np] = 1; 66 } 67 else { 68 int Q = tr[p][f]; 69 if(len[Q] == len[p] + 1) { 70 fail[np] = Q; 71 } 72 else { 73 int nQ = ++tot; 74 len[nQ] = len[p] + 1; 75 fail[nQ] = fail[Q]; 76 fail[Q] = fail[np] = nQ; 77 memcpy(tr[nQ], tr[Q], sizeof(tr[Q])); 78 while(tr[p][f] == Q) { 79 tr[p][f] = nQ; 80 p = fail[p]; 81 } 82 } 83 } 84 return; 85 } 86 87 inline void clear() { 88 for(register int i(1); i <= tot; i++) { 89 memset(tr[i], 0, sizeof(tr[i])); 90 val[i] = e[i] = fail[i] = len[i] = 0; 91 } 92 last = tot = 1; 93 tp = 0; 94 return; 95 } 96 97 void DFS(int x, int p) { 98 stk[++top] = x; 99 /// calc ans x 100 //printf("x = %d \n", x); 101 while(p < top && len[stk[p + 1]] * 2 <= len[x]) { 102 ++p; 103 } 104 if(vis[x] == Time) { 105 ans = 1ll * ans * (val[stk[p]] + 1) % MO; 106 } 107 for(int i = e[x]; i; i = edge[i].nex) { 108 int y = edge[i].v; 109 val[y] = val[x] + (vis[y] == Time); 110 DFS(y, p); 111 } 112 --top; 113 return; 114 } 115 116 inline void solve() { 117 scanf("%s", str + 1); 118 n = strlen(str + 1); 119 /*if(n <= 200) { 120 bf::solve(); 121 return; 122 }*/ 123 ++Time; 124 ans = 1; 125 for(register int i(1); i <= n; i++) { 126 insert(str[i] - 'a'); 127 } 128 for(register int i(2); i <= tot; i++) { 129 add(fail[i], i); 130 } 131 132 DFS(1, 1); /// get val 133 printf("%d\n", ans); 134 clear(); 135 return; 136 } 137 138 int main() { 139 int T; 140 scanf("%d", &T); 141 while(T--) { 142 solve(); 143 if(T) memset(str + 1, 0, n * sizeof(char)); 144 } 145 return 0; 146 }
這題很是良心的沒卡空間。