BZOJ 3636 教義問答手冊 (分治)

2022-05-07 01:39:08 字數 2289 閱讀 9320

乙個整數數列,多次詢問某段區間[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∑

j​a[

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

llog⁡n

)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 詢問...