Tsinsen Palisection

建回文树。

正反建统计一种前缀和求出所有不相交的,用总数减去就是答案数。

在这里我们可以知道一个字符串中所有回文串的个数即为num数组之和(因为以一个节点为回文串结尾的字串都是唯一的)

也可以是cnt数组的和(想想看为什么)

题目链接:http://www.tsinsen.com/ViewGProblem.page?gpid=A1393

来源是Codeforces17E,但这样会MLE所以可以使用Vector替代next数组(时间换空间)这里不给出代码。

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e6+10;
 4 const int mod=51123987;
 5 const int M=26;
 6 struct node
 7 {
 8     int num[N],cnt[N],nex[N][M],fail[N],S[N],len[N];
 9     int n,p,last;
10     int newnode(int l)
11     {
12         for(int i=0;i<M;++i)nex[p][i]=0;
13         cnt[p]=num[p]=0;
14         len[p]=l;
15         return p++;
16     }
17     
18     void init()
19     {
20         p=0;n=1;
21         newnode(0);newnode(-1);
22         last=n=0;
23         S[n]=-1;fail[0]=1;
24     }
25     
26     int getfail(int x)
27     {
28         while(S[n-len[x]-1]!=S[n])x=fail[x];
29         return x;
30     }
31     
32     int add(int c)
33     {
34         c=c-'a';
35         S[++n]=c;
36         int cur=getfail(last);
37         if(!nex[cur][c])
38         {
39             int now=newnode(len[cur]+2);
40             fail[now]=nex[getfail(fail[cur])][c];
41             nex[cur][c]=now;
42             num[now]=num[fail[now]]+1;
43         }
44         last=nex[cur][c];
45         cnt[last]++46         return num[last];
47     }
48     void count()
49     {
50         for(int i=p-1;i>=1;--i)cnt[fail[i]]+=cnt[i];
51     }
52 }T;
53 char s[N];
54 int ll[N],rr[N];
55 int main()
56 {
57     int n;long long sum=0,ans=0;
58     scanf("%d%s",&n,s);
59     T.init();
60     for(int i=n-1;i>=0;--i)
61     {
62         ll[i]=(T.add(s[i])+ll[i+1])%mod;
63     }
64     T.init();
65     for(int i=0;i<n;++i)
66     {
67         rr[i]=T.add(s[i]);sum+=rr[i];sum%=mod;
68         ans=(ans+1ll*ll[i+1]*rr[i]%mod)%mod;
69     }
70     ans=(1ll*sum*(sum-1)/2%mod-ans+mod)%mod;
71     printf("%lld\n",ans);
72     return 0;
73 }

Ps:随时注意取模。。。

posted @ 2018-01-10 21:52  大奕哥&VANE  阅读(140)  评论(0编辑  收藏  举报