Solution -「ARC 125E」Snack
阿新 • • 發佈:2021-08-23
\(\mathcal{Description}\)
Link.
把\(n\) 種零食分給 \(m\) 個人,第 \(i\) 種零食有 \(a_i\) 個;第 \(i\) 個人得到同種零食數量不超過 \(b_i\),總數量不超過 \(c_i\),求最多分出的零食數量。
\(n,m\le2\times10^5\)。
\(\mathcal{Solution}\)
很容易看出這是網路流模型:
- 源點 \(S\) 連向每種零食 \(i\),容量 \(a_i\);
- 零食 \(i\) 連向人 \(j\),容量 \(b_j\);
- 人 \(j\) 連向匯點 \(T\),容量 \(c_j\)。
答案即為 \(S\)
在這樣的網路中,我們發現容量的種類數少,而邊數很多,可以推出邊的容量與這條邊具體連線兩端結點的相關性不強。這種時候,可以嘗試手算最小割。
具體地,設零食集合 \(A\) 被割入 \(S\) 部,那麼對於一個人 \(i\),他被割入 \(S\) 部的代價為 \(c_i\),被割入 \(T\) 部的代價是 \(|A|b_i\),我們應取兩者較小值,而這果然與 \(A\) 集合具體構成不相關。所以,列舉 \(|A|\in[0,n]\),每個人一定在一段字首中被割入 \(T\) 部,在其餘情況被割入 \(S\) 部,利用單調性維護這一過程,做到複雜度 \(\mathcal O(n\log n+m\log m)\)
\(\mathcal{Code}\)
/*~Rainybunny~*/ #include <bits/stdc++.h> #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i ) #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) typedef long long LL; inline void chkmin( LL& a, const LL b ) { b < a && ( a = b ); } const int MAXN = 2e5; int n, m, b[MAXN + 5], ord[MAXN + 5]; LL a[MAXN + 5], c[MAXN + 5]; int main() { scanf( "%d %d", &n, &m ); rep ( i, 1, n ) scanf( "%lld", &a[i] ); rep ( i, 1, m ) scanf( "%d", &b[i] ), ord[i] = i; rep ( i, 1, m ) scanf( "%lld", &c[i] ); std::sort( a + 1, a + n + 1, []( const LL u, const LL v ) { return u > v; } ); std::sort( ord + 1, ord + m + 1, []( const int u, const int v ) { return 1ull * c[u] * b[v] < 1ull * c[v] * b[u]; } ); LL sa = 0, sb = 0, sc = 0, ans = 1ll << 60; rep ( i, 1, n ) sa += a[i]; rep ( i, 1, m ) sb += b[i]; for ( int i = 0, j = 1; i <= n; ++i ) { sa -= a[i]; for ( ; j <= m && 1ll * i * b[ord[j]] > c[ord[j]]; sb -= b[ord[j]], sc += c[ord[j++]] ); chkmin( ans, sa + i * sb + sc ); } printf( "%lld\n", ans ); return 0; }