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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ICPC China Nanchang National Invitational - I. Max answer(线段树+ST)

發(fā)布時間:2024/4/18 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ICPC China Nanchang National Invitational - I. Max answer(线段树+ST) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目鏈接
N個數(shù)字求一個區(qū)間使得∑i=li=ra[i]×∑i=li=rmin(a[i])\sum_{i=l}^{i=r} a[i] × \sum_{i=l}^{i=r}min(a[i])i=li=r?a[i]×i=li=r?min(a[i])最大

思路

  • 枚舉區(qū)間的最小值為a[i]a[i]a[i],根據(jù)ST表二分找到它 最左 LLL最右 RRR端點,這是保證區(qū)間[L,R][L, R][L,R]的最小值為a[i]a[i]a[i]
    preprepre記錄前綴和
    sufsufsuf記錄后綴和

找到區(qū)間之后分兩種情況

  • a[i]≥0a[i] \ge0a[i]0
    Ans=a[i]×(MaxPre[i,R]?Pre[i?1]+MaxSuf[L,i]?Suf[i])Ans = a[i]×(MaxPre[i, R]-Pre[i-1] + MaxSuf[L,i]-Suf[i])Ans=a[i]×(MaxPre[i,R]?Pre[i?1]+MaxSuf[L,i]?Suf[i])
    因為a[i]≥0a[i] \ge0a[i]0所以我們在區(qū)間[i,R][i, R][i,R]找到一個最大的前綴和, 在區(qū)間[L,i][L, i][L,i]找到一個最大的后綴和這樣就能保證值最大

  • a[i]&lt;0a[i] &lt;0a[i]<0
    和上一種情況相反
    Ans=a[i]×(MinPre[i,R]?Pre[i?1]+MinSuf[L,i]?Suf[i])Ans = a[i]×(MinPre[i, R]-Pre[i-1] + MinSuf[L,i]-Suf[i])Ans=a[i]×(MinPre[i,R]?Pre[i?1]+MinSuf[L,i]?Suf[i])
    因為a[i]&lt;0a[i] &lt;0a[i]<0所以我們在區(qū)間[i,R][i, R][i,R]找到一個最小的前綴和, 在區(qū)間[L,i][L, i][L,i]找到一個最小的后綴和這樣就能保證值最大

Ac之路很坎坷,剛開始全用ST表維護(hù)最大值最小值,結(jié)果MLE(ST很快但是空間也很高),然后把求后綴的ST表用線段樹寫,還是MLE。前后綴都帶用線段樹寫,兩個線段樹代碼重復(fù)太高而且變量名也不好起,還沒用C++寫過類,學(xué)習(xí)下杰哥用類寫的線段樹。Orz。。。

AC

#include <bits/stdc++.h> #define LL long long #define P pair<int, int> #define lowbit(x) (x & -x) #define mem(a, b) memset(a, b, sizeof(a)) #define mid ((l + r) >> 1) #define lc rt<<1 #define rc rt<<1|1 using namespace std; const int maxn = 5e5 + 5;int a[maxn]; int dp[maxn][20]; LL pre[maxn], suf[maxn]; void ST(int n) {for (int i = 1; i <= n; ++i) {dp[i][0] = a[i];}for (int j = 1; j <= log2(n); ++j) {for (int i = 1; i+(1<<j)-1 <= n; ++i) {dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);}} } LL RMQ(int l, int r) {int len = r - l + 1;int x = log2(len);return min(dp[l][x], dp[r - (1<<x)+1][x]); }class Seg{LL Max[maxn<<2], Min[maxn<<2];public: void build(int rt, int l, int r, LL a[]) {if (l == r) {Max[rt] = a[l];Min[rt] = a[l];return;}build(lc, l, mid, a);build(rc, mid+1, r, a);Max[rt] = max(Max[lc], Max[rc]);Min[rt] = min(Min[lc], Min[rc]); }public: LL query_min(int rt, int l, int r, int ql, int qr) {if (r < ql || l > qr) return 1e18;if (l >= ql && r <= qr) return Min[rt];LL tmp1 = query_min(lc, l, mid, ql, qr);LL tmp2 = query_min(rc, mid+1, r, ql, qr);return min(tmp1, tmp2);}public: LL query_max(int rt, int l, int r, int ql, int qr) {if (r < ql || l > qr) return -1e18;if (l >= ql && r <= qr) return Max[rt];LL tmp1 = query_max(lc, l, mid, ql, qr);LL tmp2 = query_max(rc, mid+1, r, ql, qr);return max(tmp1, tmp2);} }Pre, Suf;int main () {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n;scanf("%d", &n); for (int i = 1; i <= n; ++i) {scanf("%d", &a[i]);pre[i] = pre[i-1] + a[i];}for (int i = n; i >= 1; --i) {suf[i] = suf[i+1] + a[i];}ST(n);Pre.build(1, 1, n, pre);Suf.build(1, 1, n, suf);LL ans = -1e18;for (int i = 1; i <= n; ++i) {int left, right, l = i, r = n;while (l <= r) {if (RMQ(l, mid) < a[i]) r = mid - 1;else l = mid + 1;}right = r;l = 1, r = i;while (l <= r) {if (RMQ(mid, r) < a[i]) l = mid + 1;else r = mid - 1;}left = l;if (a[i] >= 0) {LL R = Pre.query_max(1, 1, n, i, right);LL L = Suf.query_max(1, 1, n, left, i);ans = max(ans, (R - pre[i-1] + L - suf[i]) * a[i]);}else {LL R = Pre.query_min(1, 1, n, i, right);LL L = Suf.query_min(1, 1, n, left, i);ans = max(ans, (R - pre[i-1] + L - suf[i]) * a[i]);}}cout << ans << endl;return 0; }

總結(jié)

以上是生活随笔為你收集整理的ICPC China Nanchang National Invitational - I. Max answer(线段树+ST)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。