傳送門題面已經很清楚了,所以就不複述了。
我們發現排列不需要儲存,只要儲存每個元素的位置 \(pos_i\) 即可,讀入 \(a\) 的時候,我們把輸入的第 \(i\) 數字在 \(b\) 中的位置 \(pos_i\) 存入 \(a_i\)。這樣問題就變成了在新的 \(a\) 陣列中查詢區間的最長連續上公升子串行。
對於離線演算法,我們想到莫隊。通過儲存當前區間內,以 \(a\) 的每個位置結尾和開頭的子串行長度 \(len_\),可以進行 \(o(1)\) 的邊界伸長。利用回滾莫隊,設定塊長為 \(\dfrac n\) 可以做到 \(o(m + n\sqrt q)\) 的總複雜度。
同樣是分塊,設塊長為 \(b\),塊數記為 \(a = \lfloor \frac nb \rfloor\)。
這個演算法和出題人的官方演算法不同,我預處理了 \(f\),\(g\),\(mx\) 三個陣列。
\(f_\) 表示從第 \(i\) 個到第 \(j\) 個整塊,外加右邊緊挨著的 \(k\) 個零散元素組成的區間 \([ib + 1, (j + 1)b + k]\) 內,以 \(k\) 為結尾的最長的滿足條件的子串行長度。
\(g_\) 表示從第 \(i\) 個到第 \(j\) 個整塊,外加左邊緊挨著的 \(k\) 個零散元素組成的區間 \([ib + 1 - k, (j + 1)b]\) 內,以 \(k\) 為開頭的最長的滿足條件的子串行長度。
\(mx_\) 表示從第 \(i\) 個到第 \(j\) 個整塊組成的區間 \([ib + 1, (j + 1)b]\) 內最長滿足條件的子串行的長度。
預處理的過程和莫隊區間伸長是一樣的。複雜度 \(o(\frac b)\)。
詢問的時候把查詢的子串行分為 \(3\) 種:
這樣可以在 \(o(b)\) 內完成一次查詢。塊長取 \(\dfrac n\) 的時候可以得到 \(o(m + n\sqrt q)\) 的複雜度。
這裡我把 \(n\),\(m\) 的意義反過來了,這裡提醒一下避免誤會。
對於 \(f\) 和 \(g\),由於空間不夠,所以採用了公用空間的手段。發現所有 \(i > j\) 的 \(f_\) 和 \(g_\) 都不存在。對於 \(f\) 來說,\(i\) 的取值為 \([0, a)\)。而 \(g\) 的 \(i\) 取值為 \((1, a)\)。所以我們可以把 \(g_\) 的值存到 \(f_\) 中去。為了防止 \(i = j\) 的時候,\(f\) 和 \(g\) 衝突的情況,我們把原本 \(f_\) 的值存到 \(f_\) 中去。這樣第 \(i\) 行,\(f\) 占用第 \((i, j]\) 列,\(g\) 占用第 \((0, i]\) 列。不產生衝突。
但是隨著塊長的變化,定義全域性變數三維陣列的行為無法滿足靈活變化的塊長的需求,頻繁的訪問定址也會增加常數,所以我們只開乙個記憶體池,然後靈活地查詢我們想要的位置的指標,在連續訪問的時候只移動指標而避免了三個下標的定址。
unsigned fpool[300000000], len[300005], mx[1005][1005];
unsigned a[300005], pos[300005], m, n, q;
unsigned stack[2005], stop(0);
unsigned a, b, c, d, tmpm;
unsigned pra, prb;
unsigned cnt(0), ans(0), tmp(0);
char use(0);
inline unsigned* f(const unsigned x, const unsigned y, const unsigned z)
signed main()
mx[i][j] = tmpm;
}unsigned* cupo(f(i, a, 1));
for (unsigned k(a* b + 1); k <= m; ++k, ++cupo)
} for (unsigned i(a - 1); i; --i)
}} memset(len, 0, ((n + 1) << 2));
for (unsigned i(1); i <= q; ++i)
while (stop) len[stack[stop--]] = 0;
printf("%u\n", ans); continue;
}--r, ans = max(ans, mx[l][r]), c = (l * b) - c + 1, d -= (r + 1) * b;
unsigned* cupo(f(l, r + 1, 1));
for (unsigned j(1), p(((r + 1)* b) + 1); j <= d; ++j, ++p, ++cupo)
for (unsigned j(1), p(l* b); j <= c; ++j, --p)
while (stop) len[stack[stop--]] = 0;
cupo = f(a - l, a - r, 1);
for (unsigned j(1); j <= c; ++j, ++cupo) ans = max(ans, *cupo);
printf("%u\n", ans);
} return wild_donkey;
}
牛客網小白月賽D
題目 水果店裡有 n個水果排成一列。店長要求顧客只能買一段連續的水果。小陽對每個水果都有乙個喜愛程度 ai,最終的滿意度為他買到的水果的喜歡程度之和。如果和為正 不管是正多少只要大於 0 即可 他就滿意了。小陽想知道在他滿意的條件下最多能買多少個水果。你能幫幫他嗎?輸入描述 第一行輸入乙個正整數 n...
牛客網 小白月賽 D題
位運算是乙個非常重要的東西。而小a最近在學習位運算,小a看到了一道很簡單的例題,是說從n個數裡面選出n 1個數要讓它們或起來的值最大,小a想知道這個答案是多少。你可以幫幫他嗎?輸入描述 第一行乙個整數n表示有n個數接下來一行n個數表示a1,a2 an第一行乙個整數n表示有n個數接下來一行n個數表示a...
EOJ 2019 2月賽 D 進製轉換
求乙個區間l,r中,在k進製表示下末尾恰有m個0的數字個數。末尾有m個0,就表示的是k m的倍數,基本容斥,就是ans x k m x k m 1 include include include include include include include include include incl...