ZJOI2010 貪吃的老鼠

2021-10-09 14:18:11 字數 3582 閱讀 9774

傳送門 to luogu

注意到老鼠的吃麵包時間是實數範圍內的,所以我們大膽地說:

∀ x1

+x2+

x3+⋯

+xn≤

ts

i\forall x_1+x_2+x_3+\cdots+x_n\le ts_i

∀x1​+x

2​+x

3​+⋯

+xn​

≤tsi

​ ,第 i

ii 個老鼠可以做到,在 t

tt 的時間內,將第 j

jj 個麵包啃掉 x

jx_j

xj​ 的長度。

或者更形象一點,老鼠更像乙個雷射**,可以持續輸出。那麼我們就要使得所有老鼠的輸出之和達到最大值 ∑i=

1npi

\sum_^ p_i

∑i=1n​

pi​ 。

所以我們使用網路流。老鼠向匯點的連邊,容量為 tsi

ts_i

tsi​

,限制其最大輸出。源點向麵包連邊,容量為 p

ip_i

pi​ ,表示這個麵包最多承受多少傷害。

但是麵包並不總是存在,所以我們將時間軸分成多個小段,每個小段內沒有麵包出現或腐爛。

接下來我們都只用考慮乙個小段內的情況。麵包向老鼠連線 +

∞+\infty

+∞的邊?這樣就會讓某個麵包同時被多個老鼠啃。畢竟每個麵包可以選擇老鼠的乙個子集。

那麼我們想辦法讓子集只能湊成乙個老鼠的攻擊力就行。比某個老鼠的攻擊力小也行,畢竟只是上限。給出方案:使用差分。將老鼠拆成字首和。

明顯這樣一來子集就一定是某個老鼠的攻擊力。但是也不能總是使用某乙個老鼠。換句話說,這些差分陣列的值是有數量限制的。比如 am−

am−1

a_m-a_

am​−am

−1​ 就只出現了 1

11 次,但是 a1−

a0

a_1-a_0

a1​−a0

​ 就會出現 m

mm 次。

所以我們處理一下這些點到匯點的連邊的容量。ai−

ai−1

a_i-a_

ai​−ai

−1​ 只會出現 m−i

+1

m-i+1

m−i+

1 次,所以其容量更改為 t(a

i−ai

−1)(

m−i+

1)

t(a_i-a_)(m-i+1)

t(ai​−

ai−1

​)(m

−i+1

) 。而麵包與「老鼠」之間的連邊呢?因為麵包只能被乙個老鼠啃,所以每個差分值最多是乙份。故二者之間連邊的容量為 t(a

i−ai

−1

)t(a_i-a_)

t(ai​−

ai−1

​)。證明這個方案的正確性,很簡單。每次找攻擊力最強的老鼠,把每個差值都去掉乙份。然後遞迴。

#include

#include

#include

#include

#include

using

namespace std;

typedef

long

long int_;

inline

intreadint()

inline

void

writeint

(int x)

inline

intqkpow

(int_ b,

int q,

int m)

const

int maxn =33;

const

int maxm = maxn*maxn<<1;

struct edge

edge

(int t,

int n)};

edge e[maxm*maxn<<1]

;int head[maxm]

, cntedge;

double c[maxm]

[maxm]

;void

newnode

(int n)

void

addedge

(int a,

int b,

double val)

queue<

int> q;

int dis[maxm]

;void

bfs(

int s,

int n)}}

int cur[maxm]

;// 當前弧

double

dfs(

int x,

double flow,

const

int&t)

if(flow == origin) dis[x]=-

1;return origin-flow;

}const

int infty =(1

<<30)

-1;double

dinic

(int s,

int t,

int n)

return flow;

}int n, m, p[maxn]

, r[maxn]

;int d[maxn]

, s[maxn]

;void

input()

for(

int i=

1; i<=m;

++i)

s[i]

=readint()

;}double tmp[maxn<<1]

;// 將時間軸割裂

void

solve()

double t =

(l+r)/2

;for

(int i=

0; i++i)

sort

(tmp,tmp+

(n<<1)

);double lst = tmp[0]

;for

(int i=

1; i<

(n<<1)

;++i)

lst = tmp[i]

;// keep on going

}// printf("t = %.6f\n",t);

// for(int i=1; i<=tot; ++i)

// for(int j=head[i]; ~j; j=e[j].nxt)

// printf("%d -> %d with %.6f\n",i,e[j].to,c[i][e[j].to]);

double mdzz =

dinic(1

,2,tot)

;// printf("%.6f\n",mdzz);

if(mdzz+

1e-7

> all)

r = t;

else l = t;

}printf

("%.6f\n"

,l);

}int

main()

ZJOI2010 貪吃的老鼠

p2570 zjoi2010 貪吃的老鼠 在ta的部落格檢視 顯然二分,最大流判定 要滿足兩個條件 1 在任一時刻,乙隻老鼠最多可以吃一塊乳酪 2 在任一時刻,一塊乳酪最多被乙隻老鼠吃。先按照乳酪的邊界進行離散化,變成num個塊,就可以知道每個時間有哪些乳酪了 把每個老鼠拆成num個點,初步 每個老...

ZJOI2010 貪吃的老鼠

點這裡看題目。注意到,這個題目的特點之一是時間是連續的。這意味著我們可以單純地關注數值而不太需要關心具體的時間。比如,乙隻老鼠在長度為 t 的時間段內,想要吃下 x k 的第 k 塊乳酪,則這一點能否做到,完全等價於 sum kx k 是否 le ts 想了好久如何轉化將時間和乳酪互相轉化,沒想到被...

ZJOI2010 數字計數

題目描述 給定兩個正整數a和b,求在 a,b 中的所有整數中,每個數碼 digit 各出現了多少次。輸入格式 輸入檔案中僅包含一行兩個整數a b,含義如上所述。輸出格式 輸出檔案中包含一行10個整數,分別表示0 9在 a,b 現了多少次。輸入輸出樣例 輸入 1 1 99 輸出 1 9 20 20 2...