日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3564 [POI2014]BAR-Salad Bar(ST表 + 二分)

發布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3564 [POI2014]BAR-Salad Bar(ST表 + 二分) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P3564 [POI2014]BAR-Salad Bar

給定一個長度為nnn的數組,里面元素只有111?1-1?1,問選出一個長度為lenlenlen的區間使得,這個區間的前綴和時刻大于零,后綴和時刻大于零,輸出最大長度lenlenlen

考慮枚舉lll端點,我們可以二分出最大的rrr,滿足pre_sumpre\_sumpre_sum時刻大于等于零,設為[l,r][l, r][l,r]

考慮枚舉RRR端點,我們可以二分出最小的LLL,滿足suc_sumsuc\_sumsuc_sum時刻大于等于零,設為[L,R][L, R][L,R]

則答案一定是在所有上述點對中的l,Rl, Rl,R中的一個,且有l≤R≤rl \leq R \leq rlRrL≤l≤RL \leq l \leq RLlR

假設我們已經把上述滿足要求的兩種點對都算出來了,考慮新開一個線段樹,

我們把第二種點對[L,R][L, R][L,R],放進線段樹上維護,在RRR點記錄符合要求的最小的LLL

考慮枚舉[l,r][l, r][l,r]點對,在區間[l,r][l, r][l,r]中尋找一個最大的RRR,使得于RRR相對應的LLL,滿足L≤lL \leq lLl,這個時候我們的答案就是R?l+1R - l + 1R?l+1的最大值了。

上述操作都利用STSTST表,然后二分一下即可,整體復雜度O(nlog?n)O (n \log n)O(nlogn)

#include <bits/stdc++.h>using namespace std;const int N = 1e6 + 10, logn = 20;int a[N], sum[N], b[N], Log[N], f[N][logn + 1], n;char str[N];vector<pair<int, int>> vt, v;void init() {Log[1] = 0, Log[2] = 1;for (int i = 3; i < N; i++) {Log[i] = Log[i / 2] + 1;} }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);init();scanf("%d %s", &n, str + 1);for (int i = 1; i <= n; i++) {a[i] = str[i] == 'p' ? 1 : -1;}for (int i = 1; i <= n; i++) {sum[i] = a[i] + sum[i - 1], f[i][0] = sum[i];}for (int j = 1; j <= logn; j++) {for (int i = 1; i + (1 << j) - 1 <= n; i++) {f[i][j] = min(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);}}for (int i = 1; i <= n; i++) {if (a[i] == -1) {continue;}int l = i, r = n;while (l < r) {int mid = l + r + 1 >> 1, s = Log[mid - i + 1];if (min(f[i][s], f[mid - (1 << s) + 1][s]) >= sum[i - 1]) {l = mid;}else {r = mid - 1;}}// printf("%d %d\n", i, l);vt.push_back({i, l});}for (int i = 1; i <= n; i++) {sum[i] = a[n - i + 1] + sum[i - 1], f[i][0] = sum[i];}for (int j = 1; j <= logn; j++) {for (int i = 1; i + (1 << j) - 1 <= n; i++) {f[i][j] = min(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);}}memset(b, 0x3f, sizeof b);for (int i = 1; i <= n; i++) {if (a[n - i + 1] == -1) {continue;}int l = i, r = n;while (l < r) {int mid = l + r + 1 >> 1, s = Log[mid - i + 1];if (min(f[i][s], f[mid - (1 << s) + 1][s]) >= sum[i - 1]) {l = mid;}else {r = mid - 1;}}b[n - i + 1] = n - l + 1;// printf("%d %d\n", n - l + 1, n - i + 1);}for (int i = 1; i <= n; i++) {f[i][0] = b[i];}for (int j = 1; j <= logn; j++) {for (int i = 1; i + (1 << j) - 1 <= n; i++) {f[i][j] = min(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);}}int ans = 0;for (auto it : vt) {int L = it.first, R = it.second;int l = it.first, r = it.second;while (L < R) {// [mid + 1, r]int mid = L + R >> 1, s = Log[r - mid];if (min(f[mid + 1][s], f[r - (1 << s) + 1][s]) <= l) {L = mid + 1;}else {R = mid;}}ans = max(ans, L - l + 1);}printf("%d\n", ans);return 0; }

總結

以上是生活随笔為你收集整理的P3564 [POI2014]BAR-Salad Bar(ST表 + 二分)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。