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:随时注意取模。。。
生命中真正重要的不是你遭遇了什么,而是你记住了哪些事,又是如何铭记的。