乙個整數數列,多次詢問某段區間[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−l
+1ja
[j])
f[i]
[j]=
max(
f[i]
[j−1
],f[
i][j
−l]+
k=j−
l+1∑
ja[
j])為了方便我們把∑k=
j−l+
1ja[
j]∑k
=j−l
+1j
a[j]
記作b[j]
b[j]
,則f[i
][j]
=max
(f[i
][j−
1],f
[i][
j−l]
+b[j
])f[
i][j
]=ma
x(f[
i][j
−1],
f[i]
[j−l
]+b[
j])空間和時間都會爆。然後想想多組詢問怎麼做。
發現l≤50l
≤50,於是就有巧妙的分治做法。
對於區間[ql
,qr]
[ql,
qr],中點是mid
mid。我們把跨越mid
mid的詢問拿出來求答案,沒有跨越的分治下去,就變成了子問題。
那麼對於乙個詢問[ql
,qr]
[ql,
qr],它的答案有兩種情況。
發現上面需要算答案的區間只有o(n
l)o(
nl)級別的且連續,可以直接預處理。
然後就做完了。時間複雜度o(n
llogn
)o(n
llogn)
。具體實現見**。
#include
using
namespace std;
char cb[
1<<18]
,*cs,
*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline
voidrd(
int&x)
const
int maxn =
100005
;const
int maxl =55;
int n, m, l, a[maxn]
, ans[maxn]
;struct query q[maxn]
, tmp1[maxn]
, tmp2[maxn]
;int fl[maxl]
[maxn]
, fr[maxl]
[maxn]
;inline
void
workl
(int l,
int r)
}inline
void
workr
(int l,
int r)
}void
cdq(
int l,
int r,
int ql,
int qr)
}for
(int i =
1; i <= it1;
++i) q[ql+i-1]
= tmp1[i]
;for
(int i =
1; i <= it2;
++i) q[ql+it1+i-1]
= tmp2[i]
;cdq
(l, mid, ql, ql+it1-1)
;cdq
(mid+
1, r, ql+it1, ql+it1+it2-1)
;}int main (
)
BZOJ3636 教義問答手冊
有三個不是那麼暴力的複雜度 o nlogn l ql qlogn 離線 然而只有離線的那個是滋磁的 4.4 等我細細道來 題意 有乙個長度為n的序列 元素有正有負 再來乙個l q組詢問,每次問區間 l,r 中,選出若干個不相交的長度正好是l的區間,使得和最大 總共有n l 1個區間嘛.再來乙個長度n...
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 詢問...