前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >义乌中学暑假集训 2021.07.14 D

义乌中学暑假集训 2021.07.14 D

作者头像
yzxoi
发布2022-09-19 13:33:27
2780
发布2022-09-19 13:33:27
举报
文章被收录于专栏:OI

义乌中学暑假集训 2021.07.14 D

给定一个 n​ 个节点,m 条边无向图,初始边权均为 1。有 k 次操作,每次操作可以选取一条边,使其边权加一。

设一条边的边权为 v​​,定义经过该边的时间为 \frac{1}{v}​​。

现有两个人,其中一个从 s_1 走到 t_1,一个从 s_2 走到 t_2,问如何操作使得两人花费总时间最少?

n,m\leq 5000,0\leq k\leq 10^9

Sol

这里给个非正解。

直接分别跑两次最短路,然后记录一下重复路径,再整个三分就过了。

然后简要说说正解。

显然两人重复路径一定是连续的一条。

那么肯定是一条长链+四条链挂在端点上。

暴力枚举长链的两个端点,然后处理出每个点到起始点/终点的距离(四条链),然后丢到一个桶里。

现在你就可以知道重复路径为长度为 i 时,四条链长度最小值。

然后对于所有的 i 分别跑次三分就好了。

这里给出非正解代码:

代码语言:javascript
复制
#include<bits/stdc++.h>
#define I inline
#define W while
#define RI register int 
#define Cn const
#define CI Cn int& 
#define gc getchar
#define pc putchar
#define LL long long
using namespace std;
#define double long double
I void read(int& x){RI f=1;char c=gc();x=0;W(!('0'<=c&&c<='9')) f=c^'-'?f:-1,c=gc();W('0'<=c&&c<='9') x=x*10+(c-'0'),c=gc();x*=f;}
I void write(int x){x<0&&(pc('-'),x=-x),x>=10&&(write(x/10),0),pc(x%10+'0');}
Cn int N=5e3+10;
int n,m,k,fir[N],nxt[N<<1],son[N<<1],w[N<<1],tot=1,s1,t1,s2,t2,F[N],vis[N],p[N],Sum,A1,A2,GG[N];
vector<int> g[N];
I void Add(CI x,CI y){nxt[++tot]=fir[x],fir[x]=tot,son[tot]=y;}
#define to son[i] 
queue<int> q;
I void Spfa(){
    RI u,i;W(!q.empty()) q.pop();memset(F,63,sizeof(F)),memset(vis,0,sizeof(vis)),vis[s1]=1,F[s1]=0,q.push(s1);W(!q.empty())
        for(u=q.front(),q.pop(),i=fir[u];i;i=nxt[i]) if(F[to]>F[u]+1) g[to].clear(),g[to].push_back(i),F[to]=F[u]+1,!vis[to]&&(q.push(to),vis[to]=1);
        else if(F[to]==F[u]+1) g[to].push_back(i);
    return ;
}
I void U(CI x){if(x==s1) return ;RI i,sz=g[x].size();for(i=0;i<sz;i++) w[g[x][i]]++,w[g[x][i]^1]++,!GG[son[g[x][i]^1]]&&(GG[son[g[x][i]^1]]=1,U(son[g[x][i]^1]),0);}
I void Spfa2(){
    RI u,i;W(!q.empty()) q.pop();memset(F,63,sizeof(F)),memset(vis,0,sizeof(vis)),vis[s2]=1,F[s2]=0,q.push(s2);W(!q.empty())
        for(u=q.front(),q.pop(),i=fir[u];i;i=nxt[i]) if(F[to]>F[u]+1) p[to]=i,F[to]=F[u]+1,!vis[to]&&(q.push(to),vis[to]=1);
        else if(F[to]==F[u]+1&&w[i]&&!w[p[to]]) p[to]=i;
    return ;
}
I void U2(CI x){if(x==s2) return ;Sum+=(w[p[x]]>0),U2(son[p[x]^1]);}
I double Q(CI x,CI y,CI z){
    if(k<=z) return 0.0+x+y-2.0*z+(z-k)*2.0+k;
    if(!(x+y-z)) return 0.0;
    RI t=k/(x+y-z);t++;k%=(x+y-z);
    if(k>z) return 1.0*(x+y-2*z-(k-z))*(1.0/t)+1.0*(k-z)*(1.0/(t+1))+2.0*z*(1.0/(t+1));
    return 1.0*(x+y-2*z)*(1.0/t)+2.0*(z-k)*(1.0/t)+2.0*k*(1.0/(t+1));
}
I double check(int x,int y,int mid){
    RI f=mid/y,g=(k-mid)/x;++f,++g;
    return (1.0-1.0/f)*y*2+(2.0*(mid%y)/f/(f+1))
            +(1.0-1.0/g)*x+(1.0*((k-mid)%x)/(g+1)/g);
}
I double calc(int x,int y){
    if(!x&&!y) return 0;
    if(!x){
        RI f=k/y;++f;
        return 2*y-(f?(1.0-1.0/f)*y*2:0)-(k%y)*(2.0/f/(f+1));
    }
    if(!y){
        RI g=k/x;++g;
        return x-(g?(1.0-1.0/g)*x:0)-(k%x)*(1.0/g/(g+1));
    }
    int l=0,r=k,i;
    while(r-l>=3){
        RI lmid=l+(r-l)/3,rmid=lmid+(r-l)/3;
        if(check(x,y,lmid)<check(x,y,rmid)) l=lmid;
        else r=rmid;
    }
    double res=0;
    for(i=l;i<=r;i++) res=max(res,check(x,y,i));
    return x+2*y-res;
}
int main(){
    RI i,x,y;for(read(n),read(m),read(k),i=1;i<=m;i++) read(x),read(y),Add(x,y),Add(y,x);
    return read(s1),read(t1),read(s2),read(t2),Spfa(),A1=F[t1],U(t1),Spfa2(),A2=F[t2],U2(t2),printf("%.17Lf\n",calc(A1+A2-Sum*2,Sum)),0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-07-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 义乌中学暑假集训 2021.07.14 D
    • Sol
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档