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;
}

原文地址:https://www.cnblogs.com/wrjlinkkkkkk/p/10427173.html

时间: 2024-07-30 02:55:06

EOJ Monthly 2019.2 E 中位数 (二分+中位数+dag上dp)的相关文章

EOJ Monthly 2019.2 E. 中位数 (二分+dfs)

题目传送门 题意: 在一个n个点,m条边的有向无环图中,求出所有从1到n 的路径的中位数的最大值 一条路径的中位数指的是:一条路径有 n 个点, 将这 n 个点的权值从小到大排序后,排在位置 ⌊n2⌋+1 上的权值. 思路: 看到权值为1~1e9,可以想到用二分答案,然后我们在验证的时候 可以将小于mid的边权设为-1,大于为1这样遍历一遍序列加起来的值 刚好为0 代码: #include<bits/stdc++.h> using namespace std; typedef long lon

EOJ Monthly 2019.2

题解 A 回收卫星 #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #defin

EOJ Monthly 2019.11 E. 数学题(莫比乌斯反演+杜教筛+拉格朗日插值)

传送门 题意: 统计\(k\)元组个数\((a_1,a_2,\cdots,a_n),1\leq a_i\leq n\)使得\(gcd(a_1,a_2,\cdots,a_k,n)=1\). 定义\(f(n,k)\)为满足要求的\(k\)元组个数,现在要求出\(\sum_{i=1}^n f(i,k),1\leq n\leq 10^9,1\leq k\leq 1000\). 思路: 首先来化简一下式子,题目要求的就是: \[ \begin{aligned} &\sum_{i=1}^n\sum_{j=1

EOJ Monthly 2019.2 (based on February Selection) D.进制转换

题目链接: https://acm.ecnu.edu.cn/contest/140/problem/D/ 题目: 思路: 我们知道一个数在某一个进制k下末尾零的个数x就是这个数整除kx,这题要求刚好末尾有m个0,还需要除去高位为0的情况,因此这题答案就是r / kx-(l-1)/kx-(r/kx+1-(l-1)/kx+1). 代码实现如下: 1 #include <set> 2 #include <map> 3 #include <deque> 4 #include &

EOJ Monthly 2019.3A

A. 钝角三角形 单点时限: 3.0 sec 内存限制: 512 MB QQ 小方以前不会判断钝角三角形,现在他会了,所以他急切的想教会你. 如果三角形的三边长分别为 a, b, c (a≤b≤c),那么当满足 a2+b2<c2 且 a+b>c 的时候,这个三角形就是一个由三边长为 a, b, c 构成的钝角三角形. 单单讲给你听肯定是不够的,为了表现自己,QQ 小方现在要考考你. 现在 QQ 小方会给你一个包含 3n 个整数的集合,分别是 {2,3,4,?3n,3n+1} ,他想让你将这个集

[EOJ Monthly] 2019.9

https://acm.ecnu.edu.cn/contest/196/ 这次是ECNU的校内选拔应该会简单一点? 下午嘉定有彩虹,在村(学)子(校)里面转了一圈,学校真大,没什么人,火烧云真美,台风 要 来 了 打开比赛,看看D:要求概率 不会是签到 看看C:这么大的模拟,不是签到 看看A:要么找规律要么SG,然后很长时间都没有人过,可能是SG,算了不管了 后来队里面有人说D是知乎原题 拿到公式开始交 逆元用费马大定理求 敲敲敲... WA WOC??为什么WA,请教了大佬队友,费马大定理会爆

EOJ Monthly 2019.11 B字母游戏

题目见:https://acm.ecnu.edu.cn/contest/231/problem/B/ 卡在第二个点和第十二个点上无数次. 和226打电话,226建议双哈希,然后一发过了....(这是226大佬的力量啊) #include<cstdio> #include<cstring> #include<algorithm> #define maxn 1005 const int mod[2]={19260817,19190504},mul[2]={29,11}; i

LA 3126 二分匹配---DAG中的最小路径应用

题意:有 n 个顾客 , 需要坐出租车从一个地方去另一个地方 , 每个顾客的出发时间.出发地点.目的地点都已给出 , 从出发地点到目的地点的时间为两地之间的路径长度 , 并且出租车要比顾客的出发时间早一分钟到达 , 问最少需要派出多少辆出租车. 解法:我们先这样来构图 , 每个顾客是一个结点,如果同一个出租车在接完客人 u 之后还来得及节客人 v , 那么就在 u 到 v 之间连一条有向边 . 由此可以发现 , 这个图是一个DAG , 那么我们就只需要找最小路径覆盖(最小路径覆盖:是指在图中找尽

二分查找&amp;&amp;二分中位数

普通二分查找 1 int bs(int L,int R,int x) 2 {//在l到r区间上查找x,找不到就返回-1 3 int l=L,r=R; 4 while(l<=r){ 5 int m=l+r>>1; 6 if(a[m]==x){ 7 return m; 8 } 9 else if(a[m]>x){ 10 r=m-1; 11 } 12 else{ 13 l=m+1; 14 } 15 } 16 return -1; 17 } 普通版很简单就不详细总结了 二分查找中位数 题意