EOJ Monthly 2019.2 E 中位数 (二分+中位数+dag上dp)

题意:

一张由 n 个点,m 条边构成的有向无环图。每个点有点权 Ai。QQ 小方想知道所有起点为 1 ,终点为 n 的路径中最大的中位数是多少。

一条路径的中位数指的是:一条路径有 n 个点,将这 n 个点的权值从小到大排序后,排在位置 n2+1 上的权值。

思路(官方题解):

考虑二分答案,我们需要验证路径最大的中位数是否 mid 。

我们把所有的点权做 1/1 变换,即 mid 的点权变为 1 ,否则变为 1 。

根据题面路径中位数的定义,我们可以发现,如果这条路径的中位数 mid ,那么做了 1/1 变换以后,这条路径上的点权和 0 。

而我们现在需要知道的问题是路径最大的中位数是否 mid ,也就是说,最大的路径点权是否 0 。

跑一遍最长路就好了。而对于 DAG ,最长路只要 dp 一下,复杂度是保证 O(m) 。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<cmath>
#include<functional>
    
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x)) 

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e6+100;
const int maxm = 1e6+100;
const int inf = 0x3f3f3f3f;

int a[maxn];
int b[maxn];
vector<int>v[maxn];
int dp[maxn];
int n,m;
int c(int x, int mid){
    return a[x]>=mid?1:-1;
}
void dpp(int x, int va,int mid){
    //printf("%d %d %d\n",x,va,mid);
    if(va<=dp[x])return;
    dp[x] = max(dp[x],va);
    //if(x==n)return;
    for(int i = 0; i < (int)v[x].size(); i++){
        dpp(v[x][i], va+c(v[x][i],mid),mid);
    }
    return;
}
bool ck(int x){
    //x = b[x];
    for(int i = 1; i <= n; i++)dp[i]=-0x3f3f3f3f;
    dpp(1,c(1,x),x);
    
    if(dp[n]>=0)return true;
    return false;
}
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++){
        int x, y;
        scanf("%d %d", &x, &y);
        v[x].pb(y);
    }
    //printf("%d",ck(5));
    int l = 0, r = 1e9;
    int ans=-1;
    while(l<=r){
        int mid = (r+l)>>1;
        //printf("%d %d %d\n",l,r,mid);
        if(ck(mid)){
            l = mid+1;
            ans=mid;
        }
        else r = mid-1;
    }
    printf("%d", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wrjlinkkkkkk/p/10427173.html