膜拜大丹(结论+二元环)
problem
有兩個(gè)國(guó)家,國(guó)家 AAA 有 nnn 座城市,國(guó)家 BBB 有 mmm 座城市,兩個(gè)國(guó)家間有若干條單向航線。
具體地,有長(zhǎng)度為 nnn 的數(shù)組 aaa 和長(zhǎng)度為 mmm 的數(shù)組 bbb。國(guó)家 AAA 的第 iii 座城市有單向航線可以到達(dá)國(guó)家 BBB 的 1~ai1\sim a_i1~ai? 號(hào)城市。國(guó)家 BBB 的第 iii 座城市有單向航線可以到達(dá)國(guó)家 AAA 的 1~bi1\sim b_i1~bi? 號(hào)城市。
定義一次膜拜為:共 n+mn+mn+m 座城市,任選一座出發(fā),沿著單向航線走,不重復(fù)經(jīng)過城市,最后回答出發(fā)城市的過程,即一個(gè)簡(jiǎn)單有向環(huán)。
要求若干次膜拜加在一起,經(jīng)過 AAA 國(guó)家的城市 iii 不超過 cic_ici? 次,經(jīng)過 BBB 國(guó)家城市 iii 不超過 did_idi? 次。
在一次膜拜中起終點(diǎn)相同,但仍然認(rèn)為起點(diǎn)只經(jīng)過了一次。
最大化膜拜次數(shù)并輸出。
solution
這個(gè)單向航線很特別,能到達(dá)對(duì)面的城市一定是從 111 開始編號(hào)的連續(xù)一段。
有個(gè)結(jié)論:每次膜拜的路線一定是個(gè)二元環(huán)。
二元環(huán)可以用 dinic\text{dinic}dinic 網(wǎng)絡(luò)流 O(n2n)O(n^2\sqrt n)O(n2n?) / 匈牙利最大匹配 O(n3)O(n^3)O(n3) 跑。
左部點(diǎn)為 AAA 國(guó)城市,右部點(diǎn)為 BBB 國(guó)城市。
當(dāng)滿足 ai≥j∧bj≥ia_i\ge j\wedge b_j\ge iai?≥j∧bj?≥i 時(shí),左部 iii 點(diǎn)和右部 jjj 點(diǎn)連一條邊。
因?yàn)闊o法通過此題,我們考慮能否模擬這個(gè)最大流的過程。
將 AAA 國(guó)城市限制當(dāng)作 (i,ai)(i,a_i)(i,ai?),BBB 國(guó)城市限制當(dāng)作 (bi,i)(b_i,i)(bi?,i),投放到二維平面上。
發(fā)現(xiàn),在二維平面圖上,對(duì)于 AAA 國(guó)城市 iii,與其有單向航線的城市都在其下方。對(duì)于 BBB 國(guó)城市 jjj,與其有單向航線的城市都在其左側(cè)。
所以,AAA 國(guó)城市 iii 只能和其右下方的 BBB 城市點(diǎn)進(jìn)行匹配,才能形成二元環(huán)。
將 AAA 國(guó)城市按 aia_iai? 分類,然后枚舉 y=ay=ay=a 常直線,像掃描線一般上移,順便加入新的 BBB 國(guó)城市點(diǎn)。
貪心地,城市 iii 會(huì)和離自己最近的 BBB 國(guó)城市匹配(這個(gè)距離單指 xxx 軸上的距離)。
大概就是更遠(yuǎn)的有更多適配情況,先將要求較嚴(yán)苛的匹配了來。
code
#include <bits/stdc++.h> using namespace std; #define maxn 500005 int n, m; int a[maxn], b[maxn], c[maxn], d[maxn]; multiset < pair < int, int > > s; vector < int > g[maxn];int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );for( int i = 1;i <= m;i ++ ) scanf( "%d", &b[i] );for( int i = 1;i <= n;i ++ ) scanf( "%d", &c[i] );for( int i = 1;i <= m;i ++ ) scanf( "%d", &d[i] );for( int i = 1;i <= n;i ++ ) g[a[i]].push_back( i );long long ans = 0;for( int i = 1;i <= m;i ++ ) {s.insert( make_pair( b[i], d[i] ) );for( int k : g[i] ) {while( ! s.empty() ) {auto it = s.lower_bound( make_pair( k, 0 ) );if( it == s.end() ) break;pair < int, int > t = *it;s.erase( it );if( t.second > c[k] ) {t.second -= c[k];ans += c[k];c[k] = 0;s.insert( t );break;}else c[k] -= t.second, ans += t.second;}}}printf( "%lld\n", ans );return 0; }總結(jié)
以上是生活随笔為你收集整理的膜拜大丹(结论+二元环)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微星 Z790 背插主板 + 配套机箱曝
- 下一篇: [学习笔记] 二分图基础定理的相关证明