我要死了。这是我做过的最恶心的题之一。
天下第一的大毒瘤。有gay毒。
我不如熊猫好多年...
题意:给定字符串,求g[i],表示:[0, i]中满足该子串既是前缀又是后缀还不重叠的子串数。
解:题面都写了KMP,想必跟KMP有关。
然后我痛苦的思考了1天无果......
我首先想到求出nex[]和f[],f[]表示可重叠的既是前缀又是后缀的子串数。
然后想找出f[]和g[]的关系,失败。
然后想到再来一个len[]表示f[]最长的那一个的长度,还是不行...
被折磨了一天,撑不住了,在吃完饭的时候开始看题解。
发现:我们要魔改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 }