EOJ Monthly 2019.2 E. 中位數 (二分+dfs)
阿新 • • 發佈:2019-03-03
contest mat cli 所有 ace set ram nbsp scanf
題目傳送門
題意:
在一個n個點,m條邊的有向無環圖中,求出所有從1到n
的路徑的中位數的最大值
一條路徑的中位數指的是:一條路徑有 n 個點,
將這 n 個點的權值從小到大排序後,排在位置 ⌊n2⌋+1 上的權值。
思路:
看到權值為1~1e9,可以想到用二分答案,然後我們在驗證的時候
可以將小於mid的邊權設為-1,大於為1這樣遍歷一遍序列加起來的值
剛好為0
代碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; #defineView CodeN 1000005 const ll INF=2e9; int n,m; int a[N]; vector<int>v[N]; int dis[N]; int vis[N]; int dfs(int mid,int x) { if(vis[x]) return dis[x]; int tmp=a[x]>=mid?1:-1; vis[x]=1; for(int i=0;i<v[x].size();i++) { int t=v[x][i]; dis[x]=max(dis[x],tmp+dfs(mid,t)); }return dis[x]; } bool check(int mid) { for(int i=1;i<=n;i++) dis[i]=-INF; memset(vis,0,sizeof(vis)); vis[1]=1; dis[1]=a[1]>=mid?1:-1; return dfs(mid,n)>=0; } int main() { while(~scanf("%d %d",&n,&m)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); while(m--) { int x,y; scanf("%d%d",&x,&y); v[y].push_back(x); } ll l=0,r=INF; ll ans=-1; while(l<=r) { ll mid=l+r>>1; if(check(mid)) { l=mid+1; ans=mid; } else r=mid-1; } printf("%lld\n",ans); } return 0; }
EOJ Monthly 2019.2 E. 中位數 (二分+dfs)