【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
",Ans);
89 }
90 
91 int main()
92 {
93         T=get();
94         while(T--)
95             Solve();
96 }
View Code
原文地址:https://www.cnblogs.com/BearChild/p/6571040.html