HNOI2016序列+資料加強版(字首和+單調棧)
普通版:題目連結
資料加強版:題目連結
資料加強版 加強版:題目連結
題目大意
給定一個數列,每次給出一個區間,求區間中所有子段的最小值之和。
題解
顯然是單調棧先跑一遍,然後接下來有若干個做法:
1.莫隊
這題莫隊解法也很神啊qwq
考慮加入點時對答案的貢獻,以右端點為例。令表示當前詢問區間中的最小值,那麼的貢獻實際上就是,其中表示區間中為右端點的貢獻,這個在單調棧的時候就可以dp出來。
於是用st表查詢最小值就可以在的時間內解決了。
2.字首和
我們考慮上面的莫隊演算法,如果詢問區間為,令最小值為,那麼考慮如果從開始不斷往左右兩邊加點,得到的答案為
顯然我們再記一個的字首和就可以回答詢問了。因此總複雜度為,可以做完資料加強版。
3.優化最值查詢
但是資料加強加強版過不了,因為瓶頸卡在了的空間複雜度上。接下來就有了一個很神仙的ST表+分塊做法。我們把原數列按照大小為分塊,分別表示從到塊開頭/結尾的最小值位置。
再考慮我們對於這些塊建立ST表,那麼如果左右端點在一個塊內,我們暴力;否則我們就可以利用上面那些東西詢問最值。這個做法空間複雜度,時間複雜度,因此大概開個10左右就行了。
下面附上加強版加強版的程式碼。
#include <bits/stdc++.h>
namespace IOStream {
const int MAXR = 10000000;
char _READ_[MAXR], _PRINT_[MAXR];
int _READ_POS_, _PRINT_POS_, _READ_LEN_;
inline char readc() {
#ifndef ONLINE_JUDGE
return getchar();
#endif
if (!_READ_POS_) _READ_LEN_ = fread(_READ_, 1, MAXR, stdin);
char c = _READ_[_READ_POS_++];
if (_READ_POS_ == MAXR) _READ_POS_ = 0;
if (_READ_POS_ > _READ_LEN_) return 0;
return c;
}
template<typename T> inline void read(T &x) {
x = 0; register int flag = 1, c;
while (((c = readc()) < '0' || c > '9') && c != '-');
if (c == '-') flag = -1; else x = c - '0';
while ((c = readc()) >= '0' && c <= '9') x = x * 10 - '0' + c;
x *= flag;
}
template<typename T1, typename ...T2> inline void read(T1 &a, T2&... x) {
read(a), read(x...);
}
inline int reads(char *s) {
register int len = 0, c;
while (isspace(c = readc()) || !c);
s[len++] = c;
while (!isspace(c = readc()) && c) s[len++] = c;
s[len] = 0;
return len;
}
inline void ioflush() { fwrite(_PRINT_, 1, _PRINT_POS_, stdout), _PRINT_POS_ = 0; fflush(stdout); }
inline void printc(char c) {
_PRINT_[_PRINT_POS_++] = c;
if (_PRINT_POS_ == MAXR) ioflush();
}
inline void prints(char *s) {
for (int i = 0; s[i]; i++) printc(s[i]);
}
template<typename T> inline void print(T x, char c = '\n') {
if (x < 0) printc('-'), x = -x;
if (x) {
static char sta[20];
register int tp = 0;
for (; x; x /= 10) sta[tp++] = x % 10 + '0';
while (tp > 0) printc(sta[--tp]);
} else printc('0');
printc(c);
}
template<typename T1, typename ...T2> inline void print(T1 x, T2... y) {
print(x, ' '), print(y...);
}
}
using namespace IOStream;
using namespace std;
typedef long long ll;
int A, B, C, P;
ll lastans;
inline int rnd() { return A = (A * B + (C ^ (int)(lastans & 0x7FFFFFFF)) % P) % P; }
const int MAXN = 3000005, M = 8, MOD = 1000000007;
int st[20][MAXN / M + 5], sta[MAXN], n, m;
int val[MAXN], lg[MAXN], tta[MAXN];
ll pre1[MAXN], pre2[MAXN], suf1[MAXN], suf2[MAXN];
inline int get_min(int x, int y) { return val[x] < val[y] ? x : y; }
inline int query_min(int l, int r) {
int tl = (l - 1) / M + 1, tr = (r - 1) / M + 1;
if (tl == tr) {
int mn = l;
for (int i = l + 1; i <= r; i++) if (val[i] < val[mn]) mn = i;
return mn;
}
if ((++tl) > (--tr)) return get_min(tta[l], sta[r]);
int x = lg[tr - tl + 1];
return get_min(get_min(st[x][tl], st[x][tr - (1 << x) + 1]), get_min(tta[l], sta[r]));
}
int main() {
read(n, m);
for (int i = 1; i <= n; i++) read(val[i]);
read(A, B, C, P);
int tp = 0;
for (int i = 1; i <= n; i++) {
for (; tp > 0 && val[sta[tp]] >= val[i]; --tp) lg[sta[tp]] = i;
pre1[i] = pre1[sta[tp]] + (ll)val[i] * (i - sta[tp]);
pre2[i] = pre2[i - 1] + pre1[i];
sta[++tp] = i;
}
while (tp > 0) lg[sta[tp--]] = n + 1;
for (int i = n; i > 0; i--) {
suf1[i] = suf1[lg[i]] + (ll)val[i] * (lg[i] - i);
suf2[i] = suf2[i + 1] + suf1[i];
}
int mm = (n + M - 1) / M;
for (int i = 1; i <= n; i++) {
if ((i - 1) % M) sta[i] = val[i] > val[sta[i - 1]] ? sta[i - 1] : i;
else sta[i] = i;
}
for (int i = n; i > 0; i--) {
if (i % M) tta[i] = val[i] > val[tta[i + 1]] ? tta[i + 1] : i;
else tta[i] = i;
}
for (int i = 1; i <= mm; i++) st[0][i] = sta[min(i * M, n)];
for (int i = 1; i < 20; i++)
for (int j = 1; j + (1 << i) - 1 <= mm; j++)
st[i][j] = get_min(st[i - 1][j], st[i - 1][j + (1 << i >> 1)]);
lg[1] = 0;
for (int i = 2; i <= mm; i++) lg[i] = lg[i >> 1] + 1;
ll res = 0;
while (m--) {
int l = rnd() % n + 1, r = rnd() % n + 1;
if (l > r) swap(l, r);
int t = query_min(l, r);
res += (lastans = (ll)(r - t + 1) * (t - l + 1) * val[t] + pre2[r] - pre2[t] - pre1[t] * (r - t) + suf2[l] - suf2[t] - suf1[t] * (t - l)) % MOD;
}
printf("%lld\n", (res % MOD + MOD) % MOD);
return 0;
}
相關文章
- 簡單題 加強版
- 單調棧和單調佇列佇列
- 單調棧 和 單調佇列佇列
- 特殊資料結構:單調棧資料結構
- 單調棧/單調佇列佇列
- P2241 統計方形(資料加強版)
- 單調棧模板
- 最新資料倉儲建模指南頂級教程加強版
- 淺談單調棧
- P6587 超超的序列 加強
- 國務院:全面加強網路安全和資料安全保護
- Java版-資料結構-棧Java資料結構
- 單調棧學習小思考
- 演算法之單調棧演算法
- 單調棧理解及應用
- 線段樹維護單調棧——區間查詢版本 & 維護遞減序列
- 簡單資料型別和引用資料型別對應棧和堆示意圖資料型別
- 虹科乾貨|Redis企業版資料庫為企業「資料安全」疊加最強Buff!Redis資料庫
- HISTOGRA - 最大矩形面積(單調棧)
- 加強版dd工具dc3dd3D
- 單調棧進階-接雨水-最大矩形
- 【筆記】線段維護單調棧筆記
- 字首和
- 資料結構—棧和佇列資料結構佇列
- 資料結構(棧和佇列)資料結構佇列
- 【資料結構】--棧和佇列資料結構佇列
- [需求建議]加強版評論外掛
- dr5.0加強版漢化版 附安裝使用教程
- (Day4)字首和&二維字首和
- 資料結構丨字首樹資料結構
- 織夢修改資料庫字首資料庫
- @資料結構C/C++版(5)《棧的順序儲存結構以及進棧和出棧操作的實現》資料結構C++
- ZBlog的資料庫表是可以設定字首-修改ZBlog資料庫字首資料庫
- 【資料結構與演算法】字首和與差分資料結構演算法
- 資料庫系列:字首索引和索引長度的取捨資料庫索引
- 銀行業應如何利用大資料加強資訊保安行業大資料
- 下秒資料受邀參加CSDN"現代資料棧峰會",活動圓滿結束
- 三國志11遊戲威力加強版遊戲