2011集訓隊出題 拆遷隊

2021-08-14 09:07:15 字數 3016 閱讀 5261

lanxisi帶領著他的拆遷隊來整治乙個街道。這個街道由n個舊房子組成,從左到右編號為1..n。每個舊房子i有乙個正整數的美觀度ai。

lanxisi希望整個街道從左到右美觀度嚴格遞增,也就是保證ai

(i。但是舊的街道明顯不符合這個要求,於是lanxisi希望拆遷一些舊房子並在原地建立新房子來滿足這一要求。但是與很多拆遷隊一樣,很多釘子戶拒絕拆遷。所以lanxisi希望能保留最多的舊房子來滿足某些釘子戶,當然,保留乙個舊房子需要給房子主人bi的賠償金。最後,總花費=整治好以後所有房子美觀度之和+賠償金之和。新的美觀值也都必須是正整數。

現在,請你求出lanxisi最多能保留多少舊房子和整治這個街道所需要的最少總花費(當然是在保留舊房子最多這個前提下的)。

1<=n<=100000,0<=ai,bi<=100000000。

先思考最樸素的o(n^2)dp是如何運作的。fi

是以i結尾最長不下降子串行的長度。 si

是以i結尾的最小總花費。fi

=max

(fi+

1)ja[j]

i],a

[j]−

j<=a[

i]−i

) si

=min

(sj+

…)(j

a[j]

i],a

[j]−

j<=a[

i]−i

,f[i

]=f[

j]+1

) 如果有:

ja[j]

−j<=a[

k]−k

那麼一定有: a[

j]k]

所以可以去掉乙個條件。

這樣就可以可以用o(n log n)的時間按照a[i]-i為關鍵字dp出f。

接著按f分層dp。

打省略號的部分可以化成三部分:

1.和j有關的部分

2.和i有關的部分

3.(a[j]-j)*i

在同一層中,如果序號j遞增,則a[j]-j遞減,不然它們就不會在同一層。

所以滿足斜率優化形式。

但是並沒有這麼簡單。

注意條件除了a[j]-j<=a[i]-i,還有

j<

i 。

在分層後,序號並不是遞增,高層的序號可能比低層小,而且a[j]-j同樣只是在同一層內有序,不同層的大小關係無法判斷。

簡化問題後可以看作對一層的連續的一段j求 mi

n(sj

+(a[

j]−j

)∗i)

到這裡可以同線段樹的分治思想來拆分詢問。

對同一層建個線段樹,每個點存這個點所代表的區間的j的單調棧。

因為線段樹只有lo

g 層,每層最多n個,所以總共是o(

nlog

n)。接著把詢問利用線段樹拆成lo

g 段,每一段二分又是lo

g ,總複雜度是o(

nlog

2n) 。

code:

#include

#include

#define ll long long

#define ld long double

#define fo(i, x, y) for(ll i = x; i <= y; i ++)

#define fd(i, x, y) for(ll i = x; i >= y; i --)

#define min(a, b) ((a) < (b) ? (a) : (b))

using namespace std;

const ll n = 1e5 + 5;

ll n, a[n], b[n], f[n], l[n], ml;

ll s[n], g[n], h[n];

ll final[n], next[n], to[n], tot;

ll st, en, ans;

ld ji(ll k, ll b, ll l, ll r)

ld jj(ll x, ll y)

int d[n * 30], d0, z[n];

struct tree t[n * 4];

void build(int i, int x, int y)

d0 = t[i].r;

if(x == y) return;

int m = x + y >> 1;

build(i + i, x, m); build(i + i + 1, m + 1, y);

}ll xx;

ll find(int i, int x, int y, int l, int r)

return h[d[as]] * xx + g[d[as]];

}int m = x + y >> 1;

if(r <= m) return find(i + i, x, m, l, r);

if(l > m) return find(i + i + 1, m + 1, y, l, r);

ll p = find(i + i, x, m, l, m), q = find(i + i + 1, m + 1, y, m + 1, r);

return min(p, q);

}int main()

for(ll l = 1, r = ml; l <= r; )

f[i] ++;

if(f[i] > ml) l[++ ml] = a[i] - i;

l[f[i]] = min(l[f[i]], a[i] - i);

}fd(i, n, 1) next[++ tot] = final[f[i]], to[tot] = i, final[f[i]] = tot;

fo(l, 1, ml)

}ans = 1e18;

fo(i, 1, n) if(f[i] == ml)

ans = min(ans, s[i] + (n - i + 1) * a[i] + (n - i) * (n - i + 1) / 2);

printf("%lld %lld", ml, ans);

}

2011集訓隊出題 happiness

高一一班的座位表是個n m的矩陣,經過乙個學期的相處,每個同學和前後左右相鄰的同學互相成為了好朋友。這學期要分文理科了,每個同學對於選擇文科與理科有著自己的喜悅值,而一對好朋友如果能同時選文科或者理科,那麼他們又將收穫一些喜悅值。作為計算機競賽教練的scp大老闆,想知道如何分配可以使得全班的喜悅值總...

2011集訓隊出題 happiness

description 高一一班的座位表是個n m的矩陣,經過乙個學期的相處,每個同學和前後左右相鄰的同學互相成為了好朋友。這學期要分文理科了,每個同學對於選擇文科與理科有著自己的喜悅值,而一對好朋友如果能同時選文科或者理科,那麼他們又將收穫一些喜悅值。作為計算機競賽教練的scp大老闆,想知道如何分...

2011集訓隊出題 跳跳棋

time limits 1000 ms memory limits 128000 kb description 跳跳棋是在一條數軸上進行的。棋子只能擺在整點上。每個點不能擺超過乙個棋子。我們用跳跳棋來做乙個簡單的遊戲 棋盤上有3顆棋子,分別在a,b,c這三個位置。我們要通過最少的跳動把他們的位置移動...