1. 程式人生 > >bzoj 3325 密碼 - Manacher

bzoj 3325 密碼 - Manacher

name 遠的 n) 相等 solid order ott zoj 字典序

題目傳送門

  需要root權限的傳送點

題目大意

  已知一個串,以每個字符為中心的最長回文串長,以及每兩個字符中間為中心的最長回文串長。求字典序最小的這樣一個串。題目保證有解。

  考慮Manacher的過程,假設當前擴展得最遠的端點是$mx$。

  $mx$之內的部分可以根據回文串的性質直接判掉,當$mx$被更新的時候才會出現新的相等關系。

  由於題目給出的是最長回文串串長,所以還需要一些不等關系。

  因為字符集很小,所以直接開數組打標記就好了。

Code

 1 #include <bits/stdc++.h>
 2 using namespace
std; 3 typedef bool boolean; 4 5 const int N = 1e5 + 3, alpha = 26; 6 7 int n; 8 int ar[N], br[N]; 9 boolean ban[N][alpha]; 10 char s[N]; 11 12 inline void init() { 13 scanf("%d", &n); 14 for (int i = 1; i <= n; i++) 15 scanf("%d", ar + i); 16 for (int
i = 1; i < n; i++) 17 scanf("%d", br + i); 18 } 19 20 inline void solve() { 21 int mx = 1, r, l; 22 for (int i = 1; i < n; i++) { 23 if (!s[i]) { 24 for ( ; ban[i][s[i]]; s[i]++); 25 s[i] += a; 26 } 27 r = i + (ar[i] >> 1
), l = i - (ar[i] >> 1); 28 if (mx < r) { 29 for (mx = mx + 1 ; mx < r; mx++) 30 s[mx] = s[2 * i - mx]; 31 s[mx] = s[2 * i - mx]; 32 } 33 if (l > 1) 34 ban[r + 1][s[l - 1] - a] = true; 35 r = i + (br[i] >> 1), l = r - br[i] + 1; 36 if (mx < r) { 37 for (mx = mx + 1 ; mx < r; mx++) 38 s[mx] = s[2 * i - mx + 1]; 39 s[mx] = s[2 * i - mx + 1]; 40 } 41 if (l > 1) 42 ban[r + 1][s[l - 1] - a] = true; 43 } 44 if (!s[n]) { 45 for ( ; ban[n][s[n]]; s[n]++); 46 s[n] += a; 47 } 48 puts(s + 1); 49 } 50 51 int main() { 52 init(); 53 solve(); 54 return 0; 55 }

bzoj 3325 密碼 - Manacher