前缀和

Description

给你一个字符串,求所有长度为偶数的前缀在整个字符串出现的次数和。

Input

共一行,一个字符串s。

Output

共一行,输出一个整数,代表长度为偶数的前缀在整个字符串出现的次数和。|S|≤200000。

Sample Input

abababc

Sample Output

6

sol:方法同string,只计算长度为偶数的前缀。
fail树的代码如下:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define N 200010
 5 #define maxn 410000
 6 using namespace std;
 7 #define int long long
 8 char s[N];
 9 int nex[N],len,p[N],ans;
10 int pre[maxn],son[maxn],now[maxn],tot,col[maxn];
11 void con(int a,int b)
12 {
13     pre[++tot]=now[a];
14     now[a]=tot;
15     son[tot]=b;
16 }
17 int dfs(int x) //统计子树大小 
18 {
19     int sz=1;
20     for(int p=now[x];p;p=pre[p])
21         sz+=dfs(son[p]);
22     return sz;
23 }
24 main(){
25    scanf("%s",s+1);
26    len=strlen(s+1);
27    nex[1]=0;
28         for(int i=2,j=0;i<=len;i++)
29         {
30             while(j && s[j+1]!=s[i]) 
31             j=nex[j];
32             if(s[j+1]==s[i]) 
33                 j++;
34             nex[i]=j;//nex[8]=5
35             con(j,i);//建一条边从j指向i,例如 5指向8,5是父亲点,8是子结点 
36         }
37    for(int i=1;i<=len;i++) 
38         if(i%2==0)
39             ans+=dfs(i);
40    printf("%lld
",ans);
41     
42 }

逆循环代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define N 200010
 5 using namespace std;
 6 char s[N];
 7 int nex[N],len,p[N],ans;
 8 int main(){
 9     scanf("%s",s+1);len=strlen(s+1);nex[1]=0;
10     for(int i=2,j=0;i<=len;i++){
11         while(j && s[j+1]!=s[i]) j=nex[j];
12         if(s[j+1]==s[i]) j++;
13         nex[i]=j;
14     }
15     for(int i=1;i<=len;i++) p[i]=1;
16     for(int i=len;i>=1;i--)  //统计子树大小,从后向前面做
17         p[nex[i]]+=p[i];
18     for(int i=1;i<=len;i++) 
19         
20 if(i%2==0) ans+=p[i];
21     printf("%d
",ans);
22 }
 
原文地址:https://www.cnblogs.com/cutepota/p/12555620.html