【EOJ Monthly 2019.02 - E】中位数(二分 ,中位数 ,−1/1变换,dp求解DAG最长路)

题干:

E. 中位数

单测试点时限: 10.0 秒

内存限制: 256 MB

“你的地图是一张白纸,所以即使想决定目的地,也不知道路在哪里。”

QQ 小方最近在自学图论。他突然想出了一个有趣的问题:

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

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

输入

第 1 行输入两个正整数 n,m (1≤n≤106,1≤m≤106 ),表示结点数量和边的数量。

第 2 行输入 n 个由空格隔开的整数 Ai (0≤Ai≤109 ),表示点权。

接下来 m 行,每行输入两个整数 x,y (1≤x,y≤n ),表示有一条 x 指向 y 的单向边,保证给出的图是联通的,可能存在重边。

输出

输出一行包含一个整数,表示最大的中位数。如果不存在任何一条起点为 1 ,终点为 n 的路径,则输出 −1 。

样例

Input

5 5
1 2 3 4 5
1 2
2 3
3 5
2 4
4 5

Output

4

解题报告:

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

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

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

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

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

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e6 + 5;
ll val[MAX],b[MAX],a[MAX];
int head[MAX];
ll dis[MAX];
int tot,flag;
bool vis[MAX];
int n,m;
struct Node {int to;int ne;
} e[MAX];
void add(int u,int v) {e[++tot].ne = head[u];e[tot].to = v;head[u] = tot;
}
void dfs(int cur,int rt) {if(vis[cur]) return ;vis[cur] = 1;if(cur == n) {flag = 1;dis[n] = val[n];return ;}dis[cur] = -0x3f3f3f3f;for(int i = head[cur]; i!=-1; i=e[i].ne) {int v = e[i].to;if(v == rt) continue;dfs(v,cur);dis[cur] = max(dis[cur],dis[v]);}dis[cur] += val[cur];
}
bool ok(ll x) {for(int i = 1; i<=n; i++) {if(a[i] >= x) val[i] = 1;else val[i] = -1;}memset(vis,0,sizeof vis);dfs(1,-1);return dis[1] >= 0;
}
int main()
{cin>>n>>m;memset(head,-1,sizeof head);for(int i = 1; i<=n; i++) scanf("%lld",val + i),a[i] = b[i] = val[i];//注意本题中点权为正 for(int u,v,i = 1; i<=m; i++) {scanf("%d%d",&u,&v);add(u,v);}memset(vis,0,sizeof vis);dfs(1,-1);if(flag == 0) {puts("-1");return 0 ;}sort(b+1,b+n+1);int x = unique(b+1,b+n+1) - b - 1;ll l = 1,r = x,mid,ans;while(l<=r) {mid = (l+r)>>1;if(ok(b[mid])) {ans = mid;l = mid+1;}else r = mid-1;}printf("%lld\n",b[ans]);return 0 ;}

为啥这样就超时。。:(有没有大佬来解释一下这样记忆化为啥不对啊,,欢迎留言区讨论)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e6 + 5;
ll val[MAX],b[MAX],a[MAX];
int head[MAX];
ll dis[MAX];
int tot,flag;
int n,m;
struct Node {int to;int ne;
} e[MAX];
void add(int u,int v) {e[++tot].ne = head[u];e[tot].to = v;head[u] = tot;
}
ll dfs(int cur,int rt) {if(dis[cur] != -0x3f3f3f3f) return dis[cur];if(cur == n) {flag = 1;dis[n] = val[n];return dis[n];}for(int i = head[cur]; i!=-1; i=e[i].ne) {int v = e[i].to;if(v == rt) continue;ll tmp = dfs(v,cur);dis[cur] = max(dis[cur],tmp);}dis[cur] += val[cur];return dis[cur];
}
bool ok(ll x) {for(int i = 1; i<=n; i++) {if(a[i] >= x) val[i] = 1;else val[i] = -1;}for(int i = 1; i<=n; i++) dis[i] = -0x3f3f3f3f;dfs(1,-1);return dis[1] >= 0;
}
int main()
{cin>>n>>m;memset(head,-1,sizeof head);for(int i = 1; i<=n; i++) scanf("%lld",val + i),a[i] = b[i] = val[i];//注意本题中点权为正 for(int u,v,i = 1; i<=m; i++) {scanf("%d%d",&u,&v);add(u,v);}for(int i = 1; i<=n; i++) dis[i] = -0x3f3f3f3f;dfs(1,-1);if(flag == 0) {puts("-1");return 0 ;}sort(b+1,b+n+1);int x = unique(b+1,b+n+1) - b - 1;ll l = 1,r = x,mid,ans;while(l<=r) {mid = (l+r)>>1;if(ok(b[mid])) {ans = mid;l = mid+1;}else r = mid-1;}printf("%lld\n",b[ans]);return 0 ;}

补充:如果要求:排在位置上的数。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e6 + 5;
ll val[MAX],b[MAX],a[MAX];
int head[MAX];
ll dis[MAX];
int tot,flag;
bool vis[MAX];
int n,m;
struct Node {int to;int ne;
} e[MAX];
void add(int u,int v) {e[++tot].ne = head[u];e[tot].to = v;head[u] = tot;
}
void dfs(int cur,int rt) {if(vis[cur]) return ;vis[cur] = 1;if(cur == n) {flag = 1;dis[n] = val[n];return ;}dis[cur] = -0x3f3f3f3f;for(int i = head[cur]; i!=-1; i=e[i].ne) {int v = e[i].to;if(v == rt) continue;dfs(v,cur);dis[cur] = max(dis[cur],dis[v]);}dis[cur] += val[cur];
}
bool ok(ll x) {for(int i = 1; i<=n; i++) {if(a[i] > x) val[i] = 1;else val[i] = -1;}memset(vis,0,sizeof vis);dfs(1,-1);return dis[1] <= 0;
}
int main()
{cin>>n>>m;memset(head,-1,sizeof head);for(int i = 1; i<=n; i++) scanf("%lld",val + i),a[i] = b[i] = val[i];//注意本题中点权为正 for(int u,v,i = 1; i<=m; i++) {scanf("%d%d",&u,&v);add(u,v);}memset(vis,0,sizeof vis);dfs(1,-1);if(flag == 0) {puts("-1");return 0 ;}sort(b+1,b+n+1);int x = unique(b+1,b+n+1) - b - 1;ll l = 1,r = x,mid,ans;while(l<=r) {mid = (l+r)>>1;if(ok(b[mid])) {ans = mid;r = mid-1;}else l = mid+1;}printf("%lld\n",b[ans]);return 0 ;}/*
4 3
1 2 3 4
1 2
2 3
3 4*/

另一种求DAG最长路的方法: 

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1000006;
int n,m,v[MAX],d[MAX],g[MAX],p[MAX],t[MAX],vis[MAX];
vector<int>G[MAX];
inline int check(int x) {for(int i=1; i<=n; ++i)p[i]=v[i]>=x?1:-1,t[i]=-1e9,g[i]=d[i];t[1]=p[1];queue<int>q;q.push(1);for(int u; !q.empty(); q.pop())for(auto v:G[u=q.front()]) {if(t[v]<t[u]+p[v]) t[v]=t[u]+p[v];if(!--g[v]) q.push(v);}return t[n]>=0;
}
int main() {cin>>n>>m;for(int i=1; i<=n; ++i)scanf("%d",v+i);if(n==1)return 0*printf("%d\n",v[1]);for(int i=1,x,y; i<=m; ++i) {scanf("%d%d",&x,&y);G[x].push_back(y),++d[y];}queue<int>q;q.push(1),vis[1]=1;for(int u; !q.empty(); q.pop())for(auto v:G[u=q.front()])if(!vis[v]) vis[v]=1,q.push(v);for(int i=1; i<=n; ++i)if(!vis[i])for(auto v:G[i]) d[v]--;int l=0,r=1e9,mid,ans=-1;while(l<=r) {mid=(l+r)>>1;if(check(mid))ans=mid,l=mid+1;elser=mid-1;}printf("%d\n",ans);
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/440717.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux桌面变成黑白,用虚拟机装了linux后开启为什么界面是黑色的呢?

20寸显示器的标准分辨率是1680*1050进入到/boot/grub/目录下&#xff0c;然后就可以看到里面有个名为menu.lst的文件&#xff0c;用vim将其打开&#xff0c;可以看到以下内容&#xff1a;# grub.conf generated by anaconda## Note that you do not have to rerun grub after m…

【EOJ Monthly 2019.01 - E】唐纳德先生与假骰子(假概率问题)

题干&#xff1a; 单测试点时限: 6.0 秒 内存限制: 1024 MB 嗨&#xff0c;唐纳德先生又来了。 他又带了一枚假骰子&#xff0c;这个骰子的各个面的点数依然是 1,2,3,4,5,6 &#xff0c;但是六个面向上的概率却不一定都是 1/6 &#xff0c;而变成了 p1,p2,p3,p4,p5,p6 。 …

linux 编译安装picocom,Linux pico命令

Linux pico命令Linux pico命令用于编辑文字文件。pico是个简单易用、以显示导向为主的文字编辑程序&#xff0c;它伴随着处理电子邮件和新闻组的程序pine而来。语法pico [-bdefghjkmqtvwxz][-n][-o][-r][-s][][文件]参数说明&#xff1a;-b 开启置换的功能。-d 开启删除的功能。…

【Hihocoder - offer编程练习赛93 套题题解】交错01串(贪心,暴力)方格矩阵高度(模拟)数对(STLmultiset)修整土地(网络流)

A&#xff1a; 题干&#xff1a; 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi要将一个01串S传输给小Ho&#xff0c;由于S非常长&#xff0c;所以小Hi决定用长度为N的2个数组A [A1, A2, ..., AN]和B [B1, B2, ..., BN]表示S。 具体来讲&#xff0c;是…

linux防火墙配置连接atlas,ATLAS在ubuntu下的安装使用

1, 根据atlas的安装文档, 首先要switch off cpu throttling.在Ubuntu系统上要首先安装cpufrequtils和cpufreqd这两个包, 也许还要安装powernowd包,然后执行sudo /usr/bin/cpufreq-selector –g. 不过幸运的是, 我在server上安装的时候发现cputhrottling已经disable了(否则在con…

【CodeForces - 545 ABCDE套题训练题解】贪心, 构造,模拟,dp,最短路树(Dijkstra+变形)

A&#xff1a; 题干&#xff1a; Input The first line contains integer n (1 ≤ n ≤ 100) — the number of cars. Each of the next n lines contains n space-separated integers that determine matrix A. It is guaranteed that on the main diagonal there ar…

linux搜索pdf文件,桌面应用|如何使用 pdfgrep 从终端搜索 PDF 文件

诸如 grep 和 ack-grep 之类的命令行工具对于搜索匹配指定正则表达式的纯文本非常有用。但是你有没有试过使用这些工具在 PDF 中搜索&#xff1f;不要这么做&#xff01;由于这些工具无法读取PDF文件&#xff0c;因此你不会得到任何结果。它们只能读取纯文本文件。顾名思义&…

【CodeForces - 546C 】Soldier and Cards (模拟)

题干&#xff1a; Two bored soldiers are playing card war. Their card deck consists of exactly n cards, numbered from 1 to n, all values are different. They divide cards between them in some manner, its possible that they have different number of cards. Th…

linux wifi 蓝牙冲突,linux 下 无线 wifi 蓝牙 无法启用

linux 下 无线 wifi 蓝牙 无法启用装了Debian squeeze 后发现无线不能打开首先想到的是装驱动于是在wiki.debian.org上查了下以重新装了下驱动#aptitude install firmware-b43-installler#modprobe b43# iwconfiglo no wireless extensions.eth0 no wireless exten…

Linux中wait接口用于延时,linux2.6驱动编写参考

1、 使用新的入口必须包含 module_init(your_init_func);module_exit(your_exit_func);老版本&#xff1a;int init_module(void);void cleanup_module(voi);2.4中两种都可以用&#xff0c;对如后面的入口函数不必要显示包含任何头文件。2、 GPLMODULE_LICENSE("Dual BSD/…

【51nod - 1108】距离之和最小 V2(曼哈顿距离,中位数性质)

题干&#xff1a; 三维空间上有N个点, 求一个点使它到这N个点的曼哈顿距离之和最小&#xff0c;输出这个最小的距离之和。 点(x1,y1,z1)到(x2,y2,z2)的曼哈顿距离就是|x1-x2| |y1-y2| |z1-z2|。即3维坐标差的绝对值之和。 收起 输入 第1行&#xff1a;点的数量N。(2 <…

Linux实验室阿里云证书,开发者云体验实验室

{"data":[{"title":"技术领域","data":[{"title":"全部","key":1,"children":[{"title":"程序语言","key":12,"children":[{"title":&qu…

【OpenJudge - noi - 7624】山区建小学(dp)

题干&#xff1a; 总时间限制: 1000ms 内存限制: 65536kB 描述 政府在某山区修建了一条道路&#xff0c;恰好穿越总共m个村庄的每个村庄一次&#xff0c;没有回路或交叉&#xff0c;任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di&#xff08;为…

nuc8i7beh安装linux随机重启,【图片】来分享一下我的NUC8I7BEH【intelnuc吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼测试来了&#xff0c;Linux 脚本&#xff0c;2G测试&#xff0c;操完这次以后休息俩礼拜。ssd随机读4kfio -filename./ran4K.log -direct1 -iodepth 1 -thread -rwrandread -ioenginepsync -bs4k -size2G -numjobs10 -runtime1000 …

【Codeforces - 找不到题号】三元环计数(bitset优化,压位)

题干&#xff1a; 给你一个二维字符矩阵&#xff0c;如果 ( i , j ) 为 表明 两点之间有一条有向边&#xff0c;为-表示没有边&#xff0c;那么你要找出所有的三元环的个数。顶点数N<1500。 解题报告&#xff1a; 考虑最暴力的方法&#xff0c;开个二维数组来存每两个顶点之…

自定义函数删除字母C语言,[编程入门]自定义函数之字符提取-题解(C语言代码)...

解题思路:输入一个字符串&#xff0c;调用函数&#xff0c;遍历字符串中每一个字符&#xff0c;看是否含有aeiou字符&#xff0c;若有&#xff0c;将其保存到另一个字符型数组中&#xff0c;在主函数中对得到的字符型数组进行排序&#xff0c;输出。注意事项:题目要求顺序输出元…

【Hihocoder - offer编程练习赛39 - D】前缀后缀查询(后缀字典树,哈希,思维)

题干&#xff1a; 时间限制:10000ms 单点时限:1000ms 内存限制:512MB 描述 给定一个包含N个单词的字典:{W1, W2, W3, ... WN}&#xff0c;其中第i个单词Wi有具有一个权值Vi。 现在小Hi要进行M次查询&#xff0c;每次查询包含一个前缀字符串Pi和一个后缀字符串Si。他希望…

c 语言 while break,26 C 语言中的break和continue - C 语言基础教程

循环语句很好用&#xff0c;但是如果循环进行到一般想要跳出循环或者结束循环怎么办&#xff1f;那么那你需要 break 和 continue 语句。1. break 和 continue 的使用语法1.1 or 循环中使用 break 和 continuebreakfor (控制循环的变量; 循环判断条件; 循环变量增减变化){语句1…

【牛客 - 21302】被3整除的子序列(线性dp)

题干&#xff1a; 给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除 答案对1e97取模 输入描述: 输入一个字符串&#xff0c;由数字构成&#xff0c;长度小于等于50 输出描述: 输出一个整数 示例1 输入 复制 132 输出 复制 3 示例2 输入 复制 …

c语言链表实现数组逆置,数组与链表等顺序表逆置

一)数组的逆置(1)算法#indclude#define N 8main(){int array[N] {100,90,80,70,60,50,50,40};int i,j,t;for(i0,jN-1;i{t array[i];array[i] array[j];array[j] t;}for(i0,iprintf("%d",qlist.data[i])}(2)时间复杂度由于只需循环N/2即可完成逆置,所以时…