【HDU5785】Interesting [Manacher]
Interesting
Time Limit: 30 Sec Memory Limit: 256 MB[Submit][Status][Discuss]
Description
Input
Output
Sample Input
2
aaa
abc
Sample Output
14
8
HINT
Source
我们先找一下这道题的本质,根据乘法分配律,我们可以使得:cntL[i]表示以 i 开始的是回文串的下标和,cntR[i]表示以 i 结束的回文串的下标和,那么这时候答案显然就是cntR[i]×cntL[i+1]。
我们再来思考一下怎么求出cntL和cntR,显然我们可以运用Manacher算法O(n)得到每一个回文半径,然后 i 对于cntL和cntR的影响显然就是一个序列上的等差数列。
接着我们再记录一下del表示公差,O(n)推一下等差数列每个位置的和即可。
Code
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<cmath>
8 using namespace std;
9 typedef long long s64;
10
11 const int ONE = (1e6+5)*2;
12 const int MOD = 1e9+7;
13 const int Niyu = 5e8+4;
14
15 int T;
16 int cntL[ONE],delL[ONE],l;
17 int cntR[ONE],delR[ONE],r;
18 char s[ONE],a[ONE];
19 int p[ONE],n;
20 int Ans;
21
22 int get()
23 {
24 int res=1,Q=1; char c;
25 while( (c=getchar())<48 || c>57)
26 if(c=='-')Q=-1;
27 if(Q) res=c-48;
28 while((c=getchar())>=48 && c<=57)
29 res=res*10+c-48;
30 return res*Q;
31 }
32
33 void Deal_first()
34 {
35 a[0] = '(';
36 for(int i=1;i<=n;i++)
37 {
38 a[2*i-1] = '#';
39 a[2*i] = s[i];
40 }
41 n = 2 * n + 1;
42 a[n] = '#'; a[n+1] = ')';
43 }
44
45 void Manacher()
46 {
47 int l = 0, id = 0;
48 for(int i=1;i<=n;i++) p[i] = 0;
49 for(int i=1;i<=n;i++)
50 {
51 if(l >= i) p[i] = min(p[id + id - i], l - i);
52 else p[i] = 1;
53 while(a[i-p[i]] == a[i+p[i]]) p[i]++;
54 if(p[i] + i > l) l = p[i]+i, id = i;
55 }
56 }
57
58 void Add(int &a,int b) {a+=b; if(a>0) a-=MOD; if(a<0) a+=MOD;}
59
60 void Solve()
61 {
62 scanf("%s",s+1); n=strlen(s+1);
63 Deal_first(); Manacher();
64
65 for(int i=1;i<=n;i++) cntL[i]=cntR[i]=delL[i]=delR[i]=0;
66
67 for(int i=1;i<=n;i++)
68 {
69 l = i-p[i]+1; r = i+p[i]-1;
70 Add(cntL[l], r); Add(cntL[i+1], -r+(i-l)); Add(delL[l+1], -1); Add(delL[i+1], 1);
71 Add(cntR[i], i); Add(cntR[r+1], -i+(r-i)); Add(delR[i+1], -1); Add(delR[r+1], 1);
72 }
73
74 for(int i=1;i<=n;i++)
75 {
76 Add(cntL[i],cntL[i-1]); Add(delL[i],delL[i-1]); Add(cntL[i],delL[i]);
77 Add(cntR[i],cntR[i-1]); Add(delR[i],delR[i-1]); Add(cntR[i],delR[i]);
78 }
79
80 n=strlen(s+1);
81 Ans = 0;
82 for(int i=1;i<n;i++)
83 {
84 Ans = Ans + (s64)cntR[2*i] *Niyu%MOD * cntL[2*(i+1)]%MOD *Niyu%MOD ;
85 Add(Ans,0);
86 }
87
88 printf("%d\n",Ans);
89 }
90
91 int main()
92 {
93 T=get();
94 while(T--)
95 Solve();
96 }