【题解】可爱路径【第四周】

update 8/22:本题已经联通了,所以不用跑连通块,不过影响不大。dp部分可以用拓扑排序预处理,不跑dfs,这样更快。

题目描述

小周猪猪手里拿到一个地图,地图显示的是一个n个点和m条边的连通的有向无环图。

现在小周猪猪需要寻找一条路径,使得这条路径是可爱路径且可爱路径的可爱度最大。

一条路径是可爱路径当且仅当可以从路径的一端走到路径的另一端,且路径经过的边数一定要大于或等于k。且路径上的每一个节点只能够经过一次。

在这里,可爱值定义为:一串n个在可爱路径上的点的点权形成一个升序序列后第int(n/2.0) + 1个数。

现在,小周猪猪想知道可爱路径的最大可爱值,请你输出这个最大可爱值。

如果地图中不存在可爱路径输出,则输出No.

输入格式

第一行:三个数,分别是n, m和 k 。表示点的个数,边的条数以及可爱路径经过边数的约束条件。

第二行:共有n个数,第i个数表示节点i的点权。

接下来m行:每行两个数x和y,表示x到y有一条有向边。

输出格式

所有可爱路径中的最大可爱值。

样例输入1:

7 8 3
46 79 97 33 22 1 122
1 2
1 5
2 3
2 6
3 4
6 4
5 7
4 7

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

分析:

首先拿到这道题,是毫无思路的。对于中位数,我们可以这样理解:设路径的长度为k,可以二分中位数x,看是否有(k+1)/2个数大于x。于是首先二分中位数。

对于每个点,若>=x,则点权为1;否则点权为-1。判断是否有一条>=k的路径,其点权的和>=0

本题可以暴搜,但会超时。其复杂度极高。于是只能用DP优化。

设dp[i][j]表示到达i点,且路径长度为j,此时的最大点权。该状态显然满足最优子结构,而且由于是DAG,所以无后效性。

我们再用dfs传入三个参数x,y,z,表示点,边数和当前权值。当z<=dp[x][y]时,直接retuen;否则更新dp[x][y],若z>=0&&y>=k,则return 1,否则继续搜索,直到回溯为止。

由于不知道起点,可以一重循环枚举。时间复杂度大概是 O ( n 2 l o g ( 2 ∗ 1 e 9 ) ) O(n^2log(2*1e9)) On2log(21e9)),但是枚举起点会有迭代,dfs也有判断有解时的剪枝。可以卡过大部分数据,有70pts。

对于剩下的n<=1e5,这个n连二维数组都开不起啊!好在只是吓人的,他告诉你每条边都是连接相邻边,其实就是单链。跑一个连通块,用前缀和判断是否有长度>=k的两个端点,且在同一连通块内,差>0。时间复杂度 O ( n l o g ( 2 ∗ 1 e 9 ) ) O(nlog(2*1e9)) Onlog(21e9))

这个问题就用朴素的方法解决了。注意开O2,否则过不了。

//dfs #include<bits/stdc++.h> using namespace std; const int N=1005; const int M=1e5+5; void read(int &x) { int f=1;x=0;char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();} x*=f; } int cnt,n,m,k,dp[N][N],g[M],gg[M],Dp[M],sum[M],con[M],maxn[M]; bool flag=1; vector<int> son[M]; void search(int x) { con[x]=cnt; for(int i=0;i<son[x].size();i++) { int y=son[x][i]; if(!con[y]) search(y); } } bool dfs(int x,int y,int z) { if(z<=dp[x][y]) return 0; dp[x][y]=z; if(z>=0&&y>=k) return 1; for(int i=0;i<son[x].size();i++) { int u=son[x][i]; if(dfs(u,y+1,z+gg[u])) return 1; } return 0; } bool check(int mid) { for(int i=1;i<=n;i++) { if(g[i]>=mid) gg[i]=1; else gg[i]=-1; } for(int j=1;j<=n;j++) { for(int k=0;k<=n;k++) { dp[j][k]=-0x3f3f3f3f; } } for(int i=1;i<=n;i++) { if(dfs(i,0,gg[i])) return 1; } return 0; } bool check2(int mid) { int tot=-0x3f3f3f3f; for(int i=1;i<=n;i++) { if(g[i]>=mid) gg[i]=1; else gg[i]=-1; sum[i]=sum[i-1]+gg[i]; if(con[i]==con[i-1]) { maxn[i]=min(maxn[i-1],sum[i]); } else maxn[i]=sum[i]; } for(int i=1;i<=n;i++) { int j=i-k; if(j>=1&&con[i]==con[j]) tot=max(tot,sum[i]-maxn[j]); if(tot>=0) return 1; } return 0; } int main() { read(n),read(m),read(k); for(int i=1;i<=n;i++) read(g[i]); for(int i=1;i<=m;i++) { int x,y; read(x),read(y); son[x].push_back(y); if(x-1!=y) flag=0; } if(flag) { for(int i=n;i>=1;i--) { if(!con[i]) { cnt++; search(i); } } int l=-1e9,r=1e9,ans=0; while(l<=r) { int mid=(1LL*(l+r))>>1; if(check2(mid)) l=mid+1,ans=mid; else r=mid-1; } if(ans==0) printf("No"); else printf("%d",ans); } else { int l=-1e9,r=1e9,ans=0; while(l<=r) { int mid=(1LL*(l+r))>>1; if(check(mid)) l=mid+1,ans=mid; else r=mid-1; } if(ans==0) printf("No"); else printf("%d",ans); } }
//topo #include<bits/stdc++.h> using namespace std; const int N=1005; const int M=1e5+5; void read(int &x) { int f=1;x=0;char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();} x*=f; } int cnt,n,m,k,dp[N][N],g[M],gg[M],Dp[M],sum[M],maxn[M]; int top,topo[N],in[N]; bool flag=1; vector<int> son[M]; void toposort() { queue<int> q; for(int i=1;i<=n;i++) if(!in[i]) q.push(i); while(q.size()) { int x=q.front();q.pop(); topo[++top]=x; for(int i=0;i<son[x].size();i++) { int y=son[x][i]; if(--in[y]==0) q.push(y); } } } bool check(int mid) { for(int i=1;i<=n;i++) { if(g[i]>=mid) gg[i]=1; else gg[i]=-1; } for(int j=1;j<=n;j++) { for(int k=0;k<=n;k++) { dp[j][k]=-0x3f3f3f3f; } } for(int i=1;i<=n;i++) { int x=topo[i]; dp[x][0]=gg[x]; for(int j=0;j<=n;j++) { if(dp[x][j]>=0&&j>=k) return 1; for(int k=0;k<son[x].size();k++) { int y=son[x][k]; dp[y][j+1]=max(dp[y][j+1],dp[x][j]+gg[y]); } } } return 0; } bool check2(int mid) { maxn[0]=0x3f3f3f3f; int tot=-0x3f3f3f3f; for(int i=1;i<=n;i++) { if(g[i]>=mid) gg[i]=1; else gg[i]=-1; sum[i]=sum[i-1]+gg[i]; maxn[i]=min(maxn[i-1],sum[i]); } for(int i=1;i<=n;i++) { int j=i-k; tot=max(tot,sum[i]-maxn[j]); if(tot>=0) return 1; } return 0; } int main() { read(n),read(m),read(k); for(int i=1;i<=n;i++) read(g[i]); for(int i=1;i<=m;i++) { int x,y; read(x),read(y); son[x].push_back(y); in[y]++; if(x-1!=y) flag=0; } if(flag) { int l=-1e9,r=1e9,ans=0; while(l<=r) { int mid=(1LL*(l+r))>>1; if(check2(mid)) l=mid+1,ans=mid; else r=mid-1; } if(ans==0) printf("No"); else printf("%d",ans); } else { toposort(); //for(int i=1;i<=top;i++) printf("%d ",topo[i]); int l=-1e9,r=1e9,ans=0; while(l<=r) { int mid=(1LL*(l+r))>>1; if(check(mid)) l=mid+1,ans=mid; else r=mid-1; } if(ans==0) printf("No"); else printf("%d",ans); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530404.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(78)  评论(0编辑  收藏  举报  
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示