P2605 ZJOI2010 基站選址

2022-03-04 03:07:48 字數 2841 閱讀 5233

有n個村莊坐落在一條直線上,第i(i>1)個村莊距離第1個村莊的距離為di。需要在這些村莊中建立不超過k個通訊基站,在第i個村莊建立基站的費用為ci。如果在距離第i個村莊不超過si的範圍內建立了乙個通訊基站,那麼就村莊被基站覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,費用為wi。現在的問題是,選擇基站的位置,使得總費用最小。

輸入格式:

輸入檔案的第一行包含兩個整數n,k,含義如上所述。

第二行包含n-1個整數,分別表示d2,d3,…,dn ,這n-1個數是遞增的。

第三行包含n個整數,表示c1,c2,…cn。

第四行包含n個整數,表示s1,s2,…,sn。

第五行包含n個整數,表示w1,w2,…,wn。

輸出格式:

輸出檔案中僅包含乙個整數,表示最小的總費用。

輸入樣例#1: 

3 2

1 22 3 2

1 1 0

10 20 30

輸出樣例#1: 

4

40%的資料中,n<=500;

100%的資料中,k<=n,k<=100,n<=20,000,di<=1000000000,ci<=10000,si<=1000000000,wi<=10000。

solution:

本題線段樹優化dp。

定義狀態$f[i][j]$表示到了$i$村莊建立第$j$個基站的最小費用(不考慮對$i+1\rightarrow n$村莊的影響),則不難得到狀態轉移方程:$f[i][j]=\min (f[k][j-1]+cost[k][i])+c[i],j-1\leq k

對於$cost[k][i]$,我們完全可以預處理出每個村莊建立基站可以覆蓋到的邊界(二分),然後對補償費用作字首和,就能在轉移時做到$o(1)$求$cost[k][i]$了,但是這樣時間複雜度還是下不去的$o(kn^2)$。

我們還是預處理出$st[i],ed[i]$分別表示$i$村莊建基站往左最多覆蓋到的村莊和往右最多覆蓋到的村莊,再用鍊錶建立覆蓋關係$ed[i]\rightarrow i$。

狀態轉移時,我們可以先滾掉後面一維。然後發現每次村莊右移引起的不會被覆蓋的點最多隻會比上個位置不會被覆蓋的點多$1$,具體來說,

當我們由$f[k]$轉移到狀態$f[i+1]$時,若$ed[p]=i$且$k\in [1,st[p])$則轉移時一定會加上覆蓋$p$的費用(不在範圍內的$k$位置轉移的值並沒有改變),那麼這個區間修改區間最值的轉移問題,想到用線段樹來優化。

設當前需要轉移的是第$j$個基站,線段樹維護$j-1$狀態在每個村莊建立基站的最小費用,由某一狀態轉移到$i$時只需要查詢$[j-1,i-1]$的最小值就好了(注意越界問題,至少要有$j-1$個基站),每次轉移完就掃一下以$i$點為$ed$的節點$p$,找到$st[p]$,對$[1,st[p]-1]$這段區間的狀態整體加上$w[p]$。

在實現時由於還得知道最後的答案,我們可以在末尾放置乙個哨兵村莊,將其設定為必須被選且覆蓋不到任何村莊,然後令村莊數$+1$、基站數$+1$,那麼每個$f[n]$就是當前狀態下的答案了,取每個狀態的最小值就好了。

**:

/*

code by 520 -- 9.25

*/#include

#define il inline

#define ll long long

#define re register

#define for(i,a,b) for(re int (i)=(a);(i)<=(b);(i)++)

#define bor(i,a,b) for(re int (i)=(b);(i)>=(a);(i)--)

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

using

namespace

std;

const

int n=100005

;int

n,k,ans,st[n],ed[n];

intd[n],c[n],s[n],w[n],f[n];

intto[n],net[n],h[n],cnt;

int minn[n<<2],lazy[n<<2

];int

gi()

il void add(int u,int v)

il void pushup(int rt)

il void pushdown(int

rt)}

void build(int l,int r,int

rt)

int m=l+r>>1

; build(lson),build(rson);

pushup(rt);

}void update(int x,int l,int r,int l,int r,int

rt) pushdown(rt);

int m=l+r>>1

;

if(l<=m) update(x,l,r,lson);

if(r>m) update(x,l,r,rson);

pushup(rt);

}int query(int l,int r,int l,int r,int

rt)int

main()

int tot=0

; for(i,

1,n)

ans=f[n];

for(i,

2,k)

ans=min(ans,f[n]);

}cout

}

P2605 ZJOI2010 基站選址

有n個村莊坐落在一條直線上,第i i 1 個村莊距離第1個村莊的距離為di。需要在這些村莊中建立不超過k個通訊基站,在第i個村莊建立基站的費用為ci。如果在距離第i個村莊不超過si的範圍內建立了乙個通訊基站,那麼就村莊被基站覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,費用為wi。現在的問題是...

ZJOI2010 基站選址

洛谷題目鏈結 真毒瘤 這個題目耗了我半天。結果是線段樹打錯了。回歸正題 線段樹 dp 首先當然是先考慮樸素 dp 啦,相信你既然都來做這題了,樸素的方程自然不用我多說,設 f i j 表示在前 i 個村莊內,第 j 個基站建在 i 處的最小費用 不考慮 i n 的賠償費用等 方程為 f i j mi...

bzoj 1835 ZJOI2010 基站選址

有n個村莊坐落在一條直線上,第i i 1 個村莊距離第1個村莊的距離為di。需要在這些村莊中建立不超過k個通訊基站,在第i個村莊建立基站的費用為ci。如果在距離第i個村莊不超過si的範圍內建立了乙個通訊基站,那麼就成它被覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,費用為wi。現在的問題是,選...