义乌集训Day 7 T4

题目链接

题目描述

mifafa 正在编写杭州城市大脑智能引擎。

杭州的道路可以被抽象成为一幅无向图。每条路的初始速度都是 1 m / s 1 m / s 。 1\mathrm{m/s}1m/s。 1m/s1m/s

mifafa 可以使用 1 RMB 1\texttt{RMB} 1RMB 让任意一条路的速度提升 1 m / s 1\mathrm{m/s} 1m/s。如果一条路的速度为 a m / s a\mathrm{m/s} am/s,那么我们需要 1 a s \frac{1}{a}\mathrm{s} a1s 才能通过这条道路。初始 mifafa 有 k RMB k\texttt{RMB} kRMB,mifafa 要把这 k RMB k\texttt{RMB} kRMB 花在升级这些道路上。

有两人的路线是s1-t1 s2-t2
,请问 mifafa 要怎么花钱,使得两位选手花费的总时间最少?当 mifafa 花完 RMB \texttt{RMB} RMB 之后,两位选手都会走花费时间最少的路。mifafa 花在每条道路上的钱都必须是非负整数。


0 ≤ n , m ≤ 5000 , 0 ≤ k ≤ 1 0 9 , 0 ≤ n , m ≤ 5000 , 0 ≤ k ≤ 1 0 9 0 \le n,m \le 5000,0 \le k \le 10^9,0≤n,m≤5000,0≤k≤10^9 0n,m5000,0k109,0n,m5000,0k109

性质1:两位选手走过的路如果有重合的地方,那么这一段必定是连续的
证明:假设他们中间的重复路段是隔开的,那么就可以直接让他们走一条共同的最短路,这样连着的就是一条连续的线段了

所以我们可以先预处理出两点之间的距离,然后枚举重复线段的两个端点,然后通过端点把整个图给连起来。

性质2:对于每个一样长度的重复路径,肯定选的是边上连的最小

然后就进行三分求单峰函数的值(需填坑)

#include<bits/stdc++.h>
#define maxn 5050
#define int long long 
#define lb long double
using namespace std;
inline int read()
{
	int  res=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
	return res*f;
} 
int n,m,k;
int head[maxn];
int dis[maxn][maxn];
struct node{
	int to,next;
}edge[maxn*2];
int tot;
inline void add(int x,int y){
	edge[++tot].to=y;
	edge[tot].next=head[x];
	head[x]=tot;
}
queue<int>q;
inline void bfs(int x)
{
	
	dis[x][x]=0;
	q.push(x);
	while(!q.empty())
    {
    	int now=q.front();q.pop();
    	for(int i=head[now];i;i=edge[i].next){
    		int to=edge[i].to;
    		if(dis[x][to]>dis[x][now]+1){
    			dis[x][to]=dis[x][now]+1;
    			q.push(to);
			}
		}
	}
}
int s1,s2,t1,t2;
int x,y;
int Ans[maxn];
lb D[maxn*2];
int id[maxn];
lb num,ans=1e8;
inline lb cale(int a,int b,int x){lb ti=0;int y=k-x;int c=x/a+1,d=x%a;lb lbc=c,lbd=d;ti+=((lb)a)/(lbc)*2.0;ti-=lbd*(1.0/(lbc))*2.0;ti+=lbd*(1.0/(lbc+1.0))*2.0;c=y/b+1,d=y%b;lbc=c,lbd=d;ti+=((lb)b)/(lbc);ti-=lbd*(1.0/(lbc));ti+=lbd*(1.0/(lbc+1.0));return ti;}
signed main()
{
//	freopen("city.in","r",stdin);freopen("city.out","w",stdout);
	n=read();m=read();k=read();
	for(int i=1;i<=m;i++)
	{
		int u,v;
		u=read();v=read();
		add(u,v);add(v,u);
	}
	memset(Ans,1e6,sizeof(Ans));
	memset(dis,1e6,sizeof(dis));
	for(int i=1;i<=n;i++)bfs(i);
	
	s1=read();t1=read();s2=read();t2=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			y=dis[i][j];
//			if(dis[s1][i]>=0x3f3f3f3f||dis[s2][i]>=0x3f3f3f3f||dis[j][t1]>=0x3f3f3f3f||dis[j][t2]>=0x3f3f3f3f)continue;
			x=dis[s1][i]+dis[s2][i]+dis[j][t1]+dis[j][t2];
			
			x=min(x,dis[s1][i]+dis[t2][i]+dis[t1][j]+dis[s2][j]);
			if(x>4*n||y>n)continue;
			if(y<0||x<0)continue;
//			cout<<x<<' '<<y<<endl;
			Ans[y]=min(Ans[y],x);
		}
	}

	 lb ans=1e8;int  tmp=(lb)(dis[s1][t1]+dis[s2][t2]);
	 if(!tmp){
cout<<0;return 0;}
	 int qt=k/tmp,kt=k%tmp;
	 ans=((lb)(tmp-kt))/((lb)qt+1)+((lb)kt)/((lb)qt+2);
	for(int i=1;i<=n;i++)
	{
		if(Ans[i]>4*n)continue;
		int l=0,r=k,lmid,rmid;
		while(r-l>=1000)
		{
			int len=r-l+1;
			lmid=l+len/3;rmid=r-len/3;
			lb ra=cale(i,Ans[i],rmid);lb la=cale(i,Ans[i],lmid);
			ans=min(ans,min(la,ra));
			if(la<ra){r=rmid;}
			else{l=lmid;}
		}
		for(int j=l;j<=r;j++)ans=min(ans,cale(i,Ans[i],j));	
	}
    printf("%.12Lf",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值