我要死了。这是我做过的最恶心的题之一。

天下第一的大毒瘤。有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 }
AC代码

相关文章:

  • 2021-10-30
  • 2021-08-27
  • 2021-10-16
  • 2022-02-20
  • 2021-12-25
  • 2021-10-16
  • 2021-09-05
  • 2022-01-01
猜你喜欢
  • 2021-08-20
  • 2022-12-23
  • 2022-12-23
  • 2021-09-08
  • 2021-09-23
  • 2022-03-08
相关资源
相似解决方案