1. 程式人生 > >[BZOJ 3521] [POI 2014] Bar

[BZOJ 3521] [POI 2014] Bar

zoj std online har main print cstring gis cnblogs

題意

  有一個長度為 n , 由 p 和 j 構成的字符串 S .

  請你找到最長的子串 T , 滿足 T 的任意一個前綴和任意一個後綴的 p 都比 j 多.

  n <= 1000000 .

分析

  建立平面直角坐標系, X 軸表示 p 的個數, Y 軸表示 j 的個數, 那麽 S 的每個前綴可以在平面上被刻畫出來.

  設 exR[i] 為以 i 開頭的子串, 最多能延伸多少位.

  設 exL[i] 為以 i 結尾的子串, 最多能多少位.

  l, r 能滿足, 當且僅當 r <=exR[l] 且 exL[r] <= l , 即兩條線段相交.

  利用連續性優化, 我們利用掃描線 + 線段樹.

  exL 與 exR 的求法類似, 如何求 exR ?

  過二維平面上的點 i , 作斜率為 1 的直線, 那麽不能達到直線上方, 即不能碰到截距比當前大 1 的直線.

  找到截距比當前大 1 的直線上的 i 的後繼 id , 那麽 exR[i] = id-1 .

實現

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <algorithm>
 6 #include <vector>
 7
#include <set> 8 using namespace std; 9 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 10 #define VI vector<int>::iterator 11 12 const int N = 1000005; 13 const int S = 2500000; 14 15 int n; char s[N]; 16 int x[N], y[N]; vector<int> g[N+N]; 17 int exL[N], exR[N]; 18 vector<int
> r[N]; int Max[S], ans; 19 20 inline int own(int x, int y) { return y - x + n + 1; } 21 22 #define Lc (x << 1) 23 #define Rc (x << 1 | 1) 24 #define M ((L + R) >> 1) 25 inline void Mod(int x, int L, int R, int pos, int sign) { 26 if (L == R) { Max[x] = (sign ? L : 0); return; } 27 pos <= M ? Mod(Lc, L, M, pos, sign) : Mod(Rc, M+1, R, pos, sign); 28 Max[x] = max(Max[Lc], Max[Rc]); 29 } 30 inline int Find(int x, int L, int R, int pos) { 31 // max_{x} (x <= pos) 32 if (pos < L) return 0; 33 if (R <= pos) return Max[x]; 34 int tmp = Find(Rc, M+1, R, pos); 35 return tmp > 0 ? tmp : Find(Lc, L, M, pos); 36 } 37 38 int main(void) { 39 #ifndef ONLINE_JUDGE 40 freopen("bar.in", "r", stdin); 41 #endif 42 43 scanf("%d", &n), scanf("%s", s+1); 44 45 g[own(0, 0)].push_back(0); 46 F(i, 1, n) { 47 x[i] = x[i-1], y[i] = y[i-1]; 48 s[i] == p ? x[i]++ : y[i]++; 49 g[own(x[i], y[i])].push_back(i); 50 } 51 52 F(i, 1, n) { 53 int u = own(x[i], y[i]) - 1; 54 VI it = lower_bound(g[u].begin(), g[u].end(), i); 55 exL[i] = (it == g[u].begin() ? 1 : *(--it) + 2); 56 } 57 F(i, 1, n) { 58 int u = own(x[i-1], y[i-1]) + 1; 59 VI it = lower_bound(g[u].begin(), g[u].end(), i); 60 exR[i] = (it == g[u].end() ? n : *it - 1); 61 } 62 63 F(i, 1, n) if (exL[i] <= i) r[exL[i]].push_back(i); 64 F(i, 1, n) { 65 for (VI it = r[i].begin(); it != r[i].end(); it++) 66 Mod(1, 1, n, *it, 1); 67 if (i <= exR[i]) { 68 int id = Find(1, 1, n, exR[i]); 69 if (id > 0) ans = max(ans, id - i + 1); 70 } 71 Mod(1, 1, n, i, 0); 72 } 73 printf("%d\n", ans); 74 75 return 0; 76 }

小結

  upper_bound 為大於 x 的最小的數.

  lower_bound 為大於等於 x 的最小的數.

  小於 x 的最小的數, 考慮 lower_bound - 1 .

  小於等於 x 的最小的數, 考慮 upper_bound - 1 .

[BZOJ 3521] [POI 2014] Bar