日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【EOJ Monthly 2019.02 - E】中位数(二分 ,中位数 ,−1/1变换,dp求解DAG最长路) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題干:

E. 中位數(shù)

單測試點(diǎn)時(shí)限: 10.0 秒

內(nèi)存限制: 256 MB

“你的地圖是一張白紙,所以即使想決定目的地,也不知道路在哪里。”

QQ 小方最近在自學(xué)圖論。他突然想出了一個(gè)有趣的問題:

一張由 n 個(gè)點(diǎn),m 條邊構(gòu)成的有向無環(huán)圖。每個(gè)點(diǎn)有點(diǎn)權(quán) Ai 。QQ 小方想知道所有起點(diǎn)為 1 ,終點(diǎn)為 n 的路徑中最大的中位數(shù)是多少。

一條路徑的中位數(shù)指的是:一條路徑有 n 個(gè)點(diǎn),將這 n 個(gè)點(diǎn)的權(quán)值從小到大排序后,排在位置 ?n2?+1 上的權(quán)值。

輸入

第 1 行輸入兩個(gè)正整數(shù) n,m (1≤n≤106,1≤m≤106 ),表示結(jié)點(diǎn)數(shù)量和邊的數(shù)量。

第 2 行輸入 n 個(gè)由空格隔開的整數(shù) Ai (0≤Ai≤109 ),表示點(diǎn)權(quán)。

接下來 m 行,每行輸入兩個(gè)整數(shù) x,y (1≤x,y≤n ),表示有一條 x 指向 y 的單向邊,保證給出的圖是聯(lián)通的,可能存在重邊。

輸出

輸出一行包含一個(gè)整數(shù),表示最大的中位數(shù)。如果不存在任何一條起點(diǎn)為 1 ,終點(diǎn)為 n 的路徑,則輸出 ?1 。

樣例

Input

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

Output

4

解題報(bào)告:

考慮二分答案,我們需要驗(yàn)證路徑最大的中位數(shù)是否 ≥mid 。

我們把所有的點(diǎn)權(quán)做 ?1/1 變換,即 ≥mid 的點(diǎn)權(quán)變?yōu)?1 ,否則變?yōu)??1 。

根據(jù)題面路徑中位數(shù)的定義,我們可以發(fā)現(xiàn),如果這條路徑的中位數(shù) ≥mid ,那么做了 ?1/1 變換以后這條路徑上的點(diǎn)權(quán)和 ≥0 。

而我們現(xiàn)在需要知道的問題是路徑最大的中位數(shù)是否 ≥mid ,也就是說,最大的路徑點(diǎn)權(quán)是否 ≥0 。

跑一遍最長路就好了。而對于 DAG ,最長路只要 dp 一下,復(fù)雜度是保證 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];//注意本題中點(diǎn)權(quán)為正 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 ;}

為啥這樣就超時(shí)。。:(有沒有大佬來解釋一下這樣記憶化為啥不對啊,,歡迎留言區(qū)討論)

#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];//注意本題中點(diǎn)權(quán)為正 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 ;}

補(bǔ)充:如果要求:排在位置上的數(shù)。

#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];//注意本題中點(diǎn)權(quán)為正 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); }

?

總結(jié)

以上是生活随笔為你收集整理的【EOJ Monthly 2019.02 - E】中位数(二分 ,中位数 ,−1/1变换,dp求解DAG最长路)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。