ICPC China Nanchang National Invitational - I. Max answer(线段树+ST)
題目鏈接
N個數字求一個區間使得∑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])最大
思路
- 枚舉區間的最小值為a[i]a[i]a[i],根據ST表二分找到它 最左 LLL 和最右 RRR端點,這是保證區間[L,R][L, R][L,R]的最小值為a[i]a[i]a[i]
preprepre記錄前綴和
sufsufsuf記錄后綴和
找到區間之后分兩種情況
-
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所以我們在區間[i,R][i, R][i,R]找到一個最大的前綴和, 在區間[L,i][L, i][L,i]找到一個最大的后綴和這樣就能保證值最大 -
a[i]<0a[i] <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]<0a[i] <0a[i]<0所以我們在區間[i,R][i, R][i,R]找到一個最小的前綴和, 在區間[L,i][L, i][L,i]找到一個最小的后綴和這樣就能保證值最大
Ac之路很坎坷,剛開始全用ST表維護最大值最小值,結果MLE(ST很快但是空間也很高),然后把求后綴的ST表用線段樹寫,還是MLE。前后綴都帶用線段樹寫,兩個線段樹代碼重復太高而且變量名也不好起,還沒用C++寫過類,學習下杰哥用類寫的線段樹。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; }總結
以上是生活随笔為你收集整理的ICPC China Nanchang National Invitational - I. Max answer(线段树+ST)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NEUQ 2015: Bitmap(二维
- 下一篇: POJ 1932 XYZZY (差分约束