义乌中学暑假集训 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$ 分别跑次三分就好了。

这里给出非正解代码:

#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;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇