傳送門 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...