# 【题解】回文串 APIO 2014 BZOJ 3676 COGS 1985 Manacher+后缀数组+二分

BZOJ和COGS上有评论说Manacher + SA的方式被卡了，也有人说自己跑了19s，我这个实现是在BZOJ上跑了10s，COGS的76组数据总共跑了3.7s。

  1 #include <cstring>
2 #include <algorithm>
3 #include <cstdio>
4 #include <cctype>
5
6 using namespace std;
7 typedef long long ll;
8 const int MAXN = 300010, LOGN = 20;
9
10 int n;
11 char str[MAXN];
12 int sas[MAXN], san;
13 int mas[MAXN<<1], man;
14
15 namespace SA {
16     int sa[MAXN], rk[MAXN], ht[MAXN];
17     int tmp1[MAXN], tmp2[MAXN], cnt[MAXN];
18     int minv[MAXN][LOGN], logn[MAXN];
19     void solve( int m ) {
20         int *x = tmp1, *y = tmp2;
21         for( int i = 0; i < m; ++i ) cnt[i] = 0;
22         for( int i = 0; i < san; ++i ) ++cnt[ x[i] = sas[i] ];
23         for( int i = 1; i < m; ++i ) cnt[i] += cnt[i-1];
24         for( int i = san-1; i >= 0; --i ) sa[--cnt[x[i]]] = i;
25         for( int k = 1; k <= san; k <<= 1 ) {
26             int p = 0;
27             for( int i = san-k; i < san; ++i ) y[p++] = i;
28             for( int i = 0; i < san; ++i ) if( sa[i] >= k ) y[p++] = sa[i]-k;
29             for( int i = 0; i < m; ++i ) cnt[i] = 0;
30             for( int i = 0; i < san; ++i ) ++cnt[x[i]];
31             for( int i = 1; i < m; ++i ) cnt[i] += cnt[i-1];
32             for( int i = san-1; i >= 0; --i ) sa[--cnt[x[y[i]]]] = y[i];
33             swap(x,y), x[sa[0]] = 0, p = 1;
34             for( int i = 1; i < san; ++i )
35                 x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++;
36             if( p == san ) break;
37             m = p;
38         }
39         for( int i = 0; i < san; ++i ) rk[i] = x[i];
40         int k = 0;
41         for( int i = 0; i < san; ++i ) {
42             if( k ) --k;
43             if( !rk[i] ) continue;
44             int j = sa[rk[i]-1];
45             while( sas[i+k] == sas[j+k] ) ++k;
46             ht[rk[i]] = minv[rk[i]][0] = k;
47         }
48         for( int k = 1; (1<<k) <= san; ++k )
49             for( int i = 0; i+(1<<k) <= san; ++i )
50                 minv[i][k] = min( minv[i][k-1], minv[i+(1<<(k-1))][k-1] );
51         k = 0;
52         for( int i = 1; i <= san; ++i ) {
53             if( (1<<(k+1)) <= i ) ++k;
54             logn[i] = k;
55         }
56     }
57     int qmin( int l, int r ) {
58         int k = logn[r-l+1];
59         return min( minv[l][k], minv[r+1-(1<<k)][k] );
60     }
61 }
62
63 void input() {
64     scanf( "%s", str ), n = strlen(str);
65     man = 0;
66     for( int i = 0; i < n; ++i ) {
67         sas[i] = str[i];
68         mas[man++] = '#', mas[man++] = str[i];
69     }
70     sas[n] = 0, san = n+1;
71     mas[man++] = '#';
72     SA::solve(128);
73 }
74
75 ll ans = 1;
76 int rd[MAXN<<1];
77 void update( int p, int k ) {
78     using namespace SA;
79     p = rk[p];
80     int LL = 0, LR = p;
81     while( LL < LR ) {
82         int mid = (LL+LR)>>1;
83         if( qmin(mid+1,p) >= k ) LR = mid;
84         else LL = mid+1;
85     }
86     int RL = p, RR = san-1;
87     while( RL < RR ) {
88         int mid = (RL+RR+1)>>1;
89         if( qmin(p+1,mid) >= k ) RL = mid;
90         else RR = mid-1;
91     }
92     ans = max( ans, ll(k)*(RL-LL+1) );
93 }
94 int cnt[26] = {0};
95 void manacher() {
96     int mx = 0, p = 0;
97     for( int i = 0; i < man; ++i ) {
98         if( i < mx ) rd[i] = min( rd[2*p-i], mx-i );
99         else rd[i] = 1;
100         while( i+rd[i] < man && i-rd[i] >= 0 && mas[i+rd[i]] == mas[i-rd[i]] ) {
101             if( islower( mas[i-rd[i]] ) ) update( (i-rd[i])/2, rd[i]+1 );
102             ++rd[i];
103         }
104         if( i+rd[i] > mx ) mx = i+rd[i], p = i;
105     }
106     for( int i = 0; i < n; ++i )
107         ans = max( ans, (ll)++cnt[str[i]-'a'] );
108     printf( "%lld\n", ans );
109 }
110
111 int main() {
112     // freopen( "apio2014_palindrome.in", "r", stdin );
113     // freopen( "apio2014_palindrome.out", "w", stdout );
114     input(), manacher();
115     return 0;
116 }

posted @ 2017-03-11 08:50  mlystdcall  阅读(370)  评论(0编辑  收藏  举报