「ZJOI2010」貪吃的老鼠
阿新 • • 發佈:2022-03-16
題目
點這裡看題目。
分析
注意到,這個題目的特點之一是時間是連續的。這意味著我們可以單純地關注數值而不太需要關心具體的時間。比如,一隻老鼠在長度為 \(t\) 的時間段內,想要吃下 \(x_k\) 的第 \(k\) 塊乳酪,則這一點能否做到,完全等價於 \(\sum_kx_k\) 是否 \(\le ts\)。
想了好久如何轉化將時間和乳酪互相轉化,沒想到被題解直接一下子解決了
不過老鼠能吃哪些乳酪還是需要考慮的問題。這很簡單,直接將時間離散成時間段即可。每一個時間段內老鼠能吃的乳酪是不會變的。在一個確定的時間段內,我們可以直接將老鼠作為網路流的結點來建圖嗎?似乎不可以,我們必須保證一個乳酪被一隻老鼠吃,但這樣會導致乳酪選中一個老鼠的子集
如果苛刻一點,我們可能會要求一種拆分方法,使得其中任何一個子集選出來都可以恰好對應到一隻老鼠。顯然這是不可能的,這必然要求 \(n\) 為 \(2\) 的一個整冪。不過,我們可以退而求其次,利用實數流很容易進行調整的性質,我們也許只需要保證老鼠可以被對應到某些子集即可?這是易於實現的,差分老鼠的速度即可。
進一步地,差分之後,我們可以建立從乳酪指向老鼠的邊。如何確定老鼠的“容量”?差分之後,第 \(k\) 快的老鼠的差分值實際上會被算到 \(m-k+1\) 次,將這個係數算到容量裡面即可。
至於這個東西怎麼滿足題目要求的,請參考他人部落格
小結:
-
注意某些變數的特點
注意到了反而不會用 -
差分想法很重要,但怎麼想到差分更重要。在這裡,主要是子集選取這樣一個結構給了我們啟發。
程式碼
#include <cmath> #include <cstdio> #include <algorithm> #define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ ) #define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- ) const int inf = 1e9; const double eps = 1e-7, INF = 1e18; const int MAXN = 1e5 + 5, MAXE = 1e6 + 5, MAXn = 100; template<typename _T> void read( _T &x ) { x = 0; char s = getchar(); bool f = false; while( s < '0' || '9' < s ) { f = s == '-', s = getchar(); } while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); } if( f ) x = -x; } template<typename _T> void write( _T x ) { if( x < 0 ) putchar( '-' ), x = -x; if( 9 < x ) write( x / 10 ); putchar( x % 10 + '0' ); } template<typename _T> _T Min( const _T a, const _T b ) { return a < b ? a : b; } struct Edge { int to, nxt; double c; } Graph[MAXE << 1]; int q[MAXN]; int dep[MAXN], cur[MAXN]; int head[MAXN], cnt = 1, ntot = 0; double tim[MAXn]; int tot = 0; int P[MAXn], R[MAXn], D[MAXn], S[MAXn]; int N, M; inline int Sgn( const double &x ) { return fabs( x ) < eps ? 0 : ( x < 0 ? -1 : 1 ); } inline void AddEdge( const int from, const int to, const double C ) { Graph[++ cnt].to = to, Graph[cnt].nxt = head[from]; Graph[cnt].c = C, head[from] = cnt; } inline void AddE( const int from, const int to, const double C ) { AddEdge( from, to, C ), AddEdge( to, from, 0 ); } bool BFS( const int S, const int T ) { int h = 1, t = 0; rep( i, 1, ntot ) dep[i] = inf; dep[q[++ t] = S] = 0; while( h <= t ) { int u = q[h ++]; for( int i = head[u], v ; i ; i = Graph[i].nxt ) if( Sgn( Graph[i].c ) && dep[v = Graph[i].to] > dep[u] + 1 ) dep[q[++ t] = v] = dep[u] + 1; } return dep[T] < inf; } double DFS( const int u, const double lin, const int T ) { if( u == T ) return lin; int v; double used = 0, ret, c; for( int &i = cur[u] ; i ; i = Graph[i].nxt ) { v = Graph[i].to, c = Graph[i].c; if( Sgn( c ) && dep[v] == dep[u] + 1 && Sgn( ret = DFS( v, Min( lin - used, c ), T ) ) ) { used += ret, Graph[i].c -= ret, Graph[i ^ 1].c += ret; if( ! Sgn( used - lin ) ) break; } } if( Sgn( used - lin ) ) dep[u] = inf; return used; } double Dinic( const int S, const int T ) { double flow = 0; while( BFS( S, T ) ) { rep( i, 1, ntot ) cur[i] = head[i]; flow += DFS( S, INF, T ); } return flow; } #define ID( t, x ) ( ( (t) - 1 ) * M + (x) + N ) bool Chk( const double T ) { cnt = 1, tot = 0; rep( i, 1, N ) { tim[++ tot] = R[i]; tim[++ tot] = D[i] + T; } std :: sort( tim + 1, tim + 1 + tot ); tot = std :: unique( tim + 1, tim + 1 + tot ) - tim - 1; ntot = N + M * ( tot - 1 ); const int s = ++ ntot, t = ++ ntot; rep( i, 1, ntot ) head[i] = 0; rep( i, 1, N ) { AddE( s, i, P[i] ); int l = std :: lower_bound( tim + 1, tim + 1 + tot, R[i] ) - tim, r = std :: lower_bound( tim + 1, tim + 1 + tot, D[i] + T ) - tim; rep( j, l, r - 1 ) rep( k, 1, M ) AddE( i, ID( j, k ), ( tim[j + 1] - tim[j] ) * S[k] ); } rep( j, 1, tot - 1 ) rep( k, 1, M ) AddE( ID( j, k ), t, ( tim[j + 1] - tim[j] ) * S[k] * ( M - k + 1 ) ); double su = 0; rep( i, 1, N ) su += P[i]; return ! Sgn( su - Dinic( s, t ) ); } int main() { int T; for( read( T ) ; T -- ; ) { read( N ), read( M ); rep( i, 1, N ) read( P[i] ), read( R[i] ), read( D[i] ); rep( i, 1, M ) read( S[i] ); std :: sort( S + 1, S + 1 + M ); per( i, M, 1 ) S[i] -= S[i - 1]; double l = 0, r = 1e9, mid; while( r - l > 1e-7 ) { mid = ( l + r ) / 2; if( Chk( mid ) ) r = mid; else l = mid; } printf( "%g\n", l ); } return 0; }