BZOJ 3790 神奇项链 (Manacher+贪心)

题目大意:给你一个串,求这个串被最少数量的回文串拼起来的次数,两个回文串可以重叠拼接,但必须保证重叠的部分完全相同

先用$Manacher$预处理出最长回文半径$p_{i}$。

再用最长双回文串的方法,处理出数组$e_{i}$,以$i$为开头最长回文串结尾的位置

在已经被遍历到的位置中,选择$e_{i}$最大的位置$maxx$,说明再拼接一次,最远能到达的位置是$maxx$,$ans++$

然后在$i~maxx$取最大的,重复上述过程,继续取$maxx$,直到串的末尾,$ans++$

这其实是个贪心,在能往下拼接的位置中,选取最远能拼到的位置,然后继续拼......

 1 #include <cmath>
 2 #include <queue>
 3 #include <vector>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #define NN 200100
 8 #define MM 1510
 9 #define ll long long
10 #define dd double  
11 #define uint unsigned int
12 #define mod 1000000007
13 #define idx(X) (X-'a')
14 #define eps (1e-9)
15 using namespace std;
16 
17 int n,nn;
18 char str[NN],a[NN];
19 int p[NN],e[NN];
20 void init()
21 {
22     memset(a,0,sizeof(a));
23     memset(e,0,sizeof(e));
24     memset(p,0,sizeof(p));
25 }
26 
27 int main()
28 {
29     //freopen("t1.in","r",stdin);
30     while(scanf("%s",str+1)!=EOF)
31     {
32         n=strlen(str+1);
33         init();
34         a[1]='#';nn=n*2+1;
35         for(int i=1;i<=n;i++)
36             a[2*i]=str[i],a[2*i+1]='#';
37         p[1]=1;int mid=1,mr=0;
38         for(int i=2;i<=nn;i++){
39             if(i<mr) 
40                 p[i]=min(p[2*mid-i],mr-i);
41             else 
42                 p[i]=1;
43             for(;a[i+p[i]]==a[i-p[i]]&&p[i]+1<=i;p[i]++);
44             if(i+p[i]>mr)
45                 mr=i+p[i],mid=i;
46             e[i-p[i]+1]=max(e[i-p[i]+1],i+p[i]-1);
47         }
48         mr=0;int ans=-1,ma=e[1],id,tmp;
49         for(int i=1;i<=nn;i++){
50             int tmp=ma;
51             for(;i<=nn&&i<=tmp;i++)
52                 ma=max(ma,e[i]);
53             ans++;
54         }
55         printf("%d\n",ans); 
56     }
57     return 0;
58 }

 

posted @ 2018-11-26 19:12  guapisolo  阅读(128)  评论(0编辑  收藏  举报