轉移就變為 g[
i]=(
∑j=1
i−1g
[j],
s[j]
≥s[i
]−mi
d)<<
1 g[i
]=(∑
j=1i
−1g[
j],s
[j]≥
s[i]
−mid
)<<
1。把
s[i]s[
i]
按從大到小排序,可知此時合法的
j j
是乙個字首。
因此把 s[
i]' role="presentation" style="position: relative;">s[i
]s[i
]離散化,作為樹狀陣列的下標維護字首和來轉移。
此時 d
p d
p複雜度 o(
nklogn
) o(n
klogn
),仍然不能通過。
進一步地,我們會發現:g[i]g
[i
]中為 tru
e tru
e的部分一定是一段連續的區間,只需要用區間的左右邊界來表示。
容易證明,一開始 g[
0]= g[0
]=
滿足條件,之後的轉移只涉及上述兩種運算,因此也滿足條件。
此時就可設 g[
i]= g[i
]=
,初始時 g[
0]= g[0
]=
,則:
因此計算 g[i]g
[i
]的部分就被優化掉了,dpdp
的時間複雜度 o(
nlogn)o(
nlogn
)。
#include
#include
#include
#include
#include
using
namespace
std;
namespace inout
inline
int get()
};using
namespace inout;
const
int m = 15005;
const
int maxn = 0x3f3f3f3f;
int n, k, m, l = maxn, r = -maxn, ans;
int f[m], g[m], sum[m], to[m], b[m];
inline
int max(int x, int y)
inline
int min(int x, int y)
inline
void ckmin(int &x, int y)
inline
void ckmax(int &x, int y)
struct line
line(int l, int r):
l(l), r(r) {}
inline
void
operator += (const line &x)
}c[m], h[m];
const line inf = line(maxn, -maxn);
inline line right(const line &x)
inline
void modify(int x, const line &y)
inline line query(int x)
inline
bool check(int mid)
return h[n - 1].r == k;
}int main()
sort(b + 1, b + n + 2);
m = unique(b + 1, b + n + 2) - b - 1;
for (int i = 0; i <= n; ++i)
to[i] = lower_bound(b + 1, b + m + 1, -sum[i]) - b;
++n;
while (l <= r)
printf("%d\n", ans);
return
0;}
日常訓練 分割田地
地主某君有一塊由2 n個柵格組成的土地,有k個兒子,現在地主快要終老了,要把這些土地分給這些兒子。分給每個兒子的土地最小的單位是乙個柵格,同時,分給同乙個兒子的土地要求要相鄰連續的。地主覺得分給某個兒子的土地面積至少有乙個柵格,但是具體多少可以隨意。請問,聰明的你,能夠算出地主一共有多少種分土地的方...
CDOJ 1157 數列 seq 分塊
題意 給出乙個數列,兩種操作 1.修改操作 把數列中第i個數改為x 2.詢問操作 給定乙個位置i,問數列中有多少個位置j j i 滿足位置i與位置j間所有的數都不超過ai與aj的較大值。簡單來說,操作2分為兩部分 1.位置i右邊相鄰連續的比它小的數字個數 2.位置i右邊不減序列長度 直接將數列分塊,...
Seq(規律 等差數列)
剛開始我還沒什麼頭緒,估計一看就是規律吧,結果打了一下表 然後發現這樣寫 然後很明顯的等差數列就出來了,最後通式一帶判斷一下餘數和計算行數就ac了 include include include include include include include include include incl...