有三個不是那麼暴力的複雜度
o(nlogn*l + ql + qlogn) // 離線
然而只有離線的那個是滋磁的》..<
4..4
等我細細道來
題意:有乙個長度為n的序列(元素有正有負),再來乙個l
q組詢問,每次問區間[l,r]中,選出若干個不相交的長度正好是l的區間,使得和最大
總共有n-l+1個區間嘛..再來乙個長度n-l+1的序列b,表示原序列a中每個長度正好為l的區間的價值。說人話就是b[
i]=∑
i+l−
1j=i
a[i]
那題意就變成了,每次詢問b中的乙個區間,在這個區間中選若干個數,在滿足任意兩個元素的下標的差的絕對值都》=l的條件下,使得被選中的值之和最大(這轉換很顯然啊》..《其實不轉換直接來也可以)
我們想要知道乙個區間的答案並修改…第一眼感覺是線段樹,可惜合併起來就非常困難啦…如果只知道兩個區間的答案,要拼起來,顯然是不可以的,因為你並不能保證左邊那個區間的最右邊的被選元素和右邊那個區間的最左邊的被選元素沒有靠得太近。那麼用乙個矩陣f[x][y]表示乙個區間的資訊,表示這個區間,刪去左邊的x個元素和右邊的y個元素後的答案,這樣就能合併啦》..x][y
]=ma
xl−1
i=0(
flef
t[x]
[i]+
frig
ht[l
−1−i
][y]
) 合併兩個區間的時間是o(l^3)於是就有了o(l^3nlogn)的做法,這只能做l較小的情況
如果只有乙個詢問,顯然有o(n)演算法。設序列為b,f[i]為前i個數的答案,那麼 f[
i]=m
ax(f
[i−1
],f[
i−l]
+b[i
])(i
>=l)
f[i]=ma
x(f[
i−1]
,b[i
])(i
如果我們知道了[l, r], [l, r + 1], [l, r + 2], …, [l, r + l - 1]的答案和b[r+l],就能得到[l, r + l]的答案,那就分塊吧。
把序列分成sqrt(n/l)塊,每塊裡選擇l個連續的特殊點,對於每個特殊點,預處理出所有以這個特殊點為左端點的詢問的答案,預處理的複雜度是o(nsqrt(nl))。處理乙個詢問[l, r]時,找出l右邊離l最近的那一段l個特殊點,然後移過來(分的是sqrt(n/l)塊,所以移動距離是sqrt(nl)),那麼處理乙個詢問就是o(sqrt(nl)),總時間複雜度還是sqrt(nsqrt(nl))
離線處理所有詢問。
當前區間是[x,y]時,只處理經過mid = (x + y) / 2的詢問,剩下的只存在於左半或右半的詢問在左右兩半遞迴下去。
那麼怎麼處理經過mid的詢問呢?
o((y-x)l)時間內,處理出所有[i, j] (x <= i <= j && mid - l < j <= mid)的答案和[i, j] (mid < i <= mid + l && i <= j <= y)的答案
現在來看乙個經過mid的詢問[ql, qr],你需要將區間[ql, m]和[m+1, qr]合併起來,不過不是o(l^3)而是o(l)因為你只想知道f[0][0]的值
所以這題就ac了!>..<
#include
int a[100001], n, l, out[100001], dp[50][100001];
struct query
q[100001], tmpq[100001];
int i()
void init()
inline int max(int
x, int
y)void nirobc(int al, int ar, int ql, int qr)
int dl = ql - 1, dr = qr + 1;
for (int i = ql; i <= qr; i++)
if (q[i].r <= m)
tmpq[++dl] = q[i];
else
if (q[i].l > m)
tmpq[--dr] = q[i];
else
for (int i = ql; i <= dl; i++)
q[i] = tmpq[i];
for (int i = dr; i <= qr; i++)
q[i] = tmpq[i];
nirobc(al, m, ql, dl), nirobc(m + 1, ar, dr, qr);
}int main()
; else
if (r - l + 1
<= l)
else}}
nirobc(l, n, 1, qq);
for (int i = 1; i <= q; i++)
printf("%d\n", out[i]);
return
0;}
BZOJ3636 教義問答手冊
傳送門乙個整數序列,給定若干詢問,每個詢問形如 在 l i,r i 中選若干個長度為 l 的不相交的區間,使得其和最大。比較容易寫出 mathcal o n 2 的 dp 定義 f 表示區間 l,r 的最大答案,那麼就有轉移方程 f max f sum ra i 預處理 mathcal o n 2 ...
BZOJ 3636 教義問答手冊
目錄傳送門 無論多麼麻煩的 寫完過後都要耐著性子檢查。首先有樸素 n 2 的 mathtt 感覺這個思路太神辣!對區間 1,n 進行分治。考慮在詢問 i 第一次覆蓋區間 text 時計算這個詢問。為什麼這是正確的?其實也就是為什麼 l,r 一定覆蓋這個詢問?容易想到如果 l,r 未覆蓋詢問 i 詢問...
BZOJ 3636 教義問答手冊 (分治)
乙個整數數列,多次詢問某段區間 li ri li ri 內,選出若干個長度為l l且不相交的連續段使選出來的數和最大。首先想樸素的區間dpd p設f i j f i j 表示區間 i,j i j 的答案。o n 2 o n2 轉移比較顯然。f i j ma x f i j 1 f i j l k j...