洛谷 P4926 [1007] 倍杀测量者

[1007] 倍杀测量者

题目描述

今天 Scarlet 在机房有幸目睹了一场别开生面的 OI 训练。因为一些奇妙的 SPJ,比赛中所有选手的得分都是正实数(甚至没有上限)。

当一位选手 A 的分数不小于选手 B 的分数 k k k k > 0 k>0 k>0)倍时,我们称选手 A k k k 倍杀 了选手 B,选手 B 选手 A k k k 倍杀 了。

更奇妙也更激动人心的是,训练前有不少选手立下了诸如 “我没 k k k 倍杀选手 X,我就女装”,“选手 Y 把我 k k k 倍杀,我就女装” 的 Flag。

知道真相的良心教练 Patchouli 为了维持机房秩序,放宽了选手们的 Flag 限制。Patchouli 设定了一个 常数 T T T,立下 “我没 k k k 倍杀选手 X 就女装” 的选手只要成功 k − T k - T kT 倍杀了选手 X,就不需要女装。同样的,立下 “选手 Y 把我 k k k 倍杀我就女装” 的选手只要没有成功被选手 Y k + T k+T k+T 倍杀,也不需要女装。

提前知道了某些选手分数和具体 Flag 的 Scarlet 实在不忍心看到这么一次精彩比赛却没人女装,为了方便和 Patchouli 交易,Scarlet 想要确定最大的实数 T T T 使得赛后一定有选手收 Flag 女装。

输入格式

第一行三个整数 n , s , t n,s,t n,s,t,分别表示机房内选手人数,选手立下的 Flag 总数和 Scarlet 已知的选手分数的数量。 n n n 位选手从 1 1 1 开始编号至 n n n,编号为 k k k 的选手被称为选手 k k k

接下来 s s s 行,每行四个整数 o , A , B , k o,A,B,k o,A,B,k。其中 o = 1 o=1 o=1 表示选手 A 立下了 “我没 k k k 倍杀选手 B 就女装” 的 Flag, o = 2 o=2 o=2 表示选手 A 立下了 “选手 B 把我 k k k 倍杀我就女装” 的 Flag。

接下来 t t t 行,每行两个整数 C , x C,x C,x,表示 Scarlet 已知选手 C C C 的分数为 x x x

输出格式

若存在能保证赛后有选手女装的最大的 T T T,则输出 T T T,只有当输出与答案的绝对误差不超过 1 0 − 4 10^{-4} 104 时才被视作正确输出。

若不存在,输出 -1

样例 #1

样例输入 #1

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

样例输出 #1

-1

样例 #2

样例输入 #2

3 2 3
1 2 1 10
2 2 3 6
1 1
2 6
3 9

样例输出 #2

3.9999993984

提示

  • 对于 30 % 30\% 30% 的数据, n ≤ 5 n\leq5 n5 s ≤ 2 s\leq 2 s2
  • 对于另 40 % 40\% 40% 的数据,保证 t = n t=n t=n
  • 对于 100 % 100\% 100% 的数据, 1 ≤ n , s ≤ 1000 1\leq n,s\leq 1000 1n,s1000 1 ≤ A , B , C , t ≤ n 1\leq A,B,C,t\leq n 1A,B,C,tn 1 ≤ k ≤ 10 1\leq k\leq 10 1k10 1 ≤ x ≤ 1 0 9 1\leq x\leq 10^9 1x109。保证输入中的 C C C 两两不同。
#include<bits/stdc++.h>
using namespace std;
struct aty {
	int v;
	double w;
	int op;
};
vector<aty> E[1100];
int n,m,u,v,w,fw[5005],op,T,s,t,o,A,B,K,C,X;
double dis[5005];
bool vis[5005];
int check(double T) {
	queue<int> q;
	for(int i=0;i<=n+1;i++){
		dis[i]=INT_MAX;
		vis[i]=0;
		fw[i]=0;
	}
	dis[n+1]=0;
	fw[n+1]=1;
	q.push(n+1);
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=0; i<E[u].size(); i++) {
			double w;
			if(E[u][i].op==2) w=log(E[u][i].w+T);
			else if(E[u][i].op==1) w=-log(E[u][i].w-T);
			else w=E[u][i].w;
			if(dis[u]+w<dis[E[u][i].v]) {
				dis[E[u][i].v]=dis[u]+w;
				if (!vis[E[u][i].v]) {
					fw[E[u][i].v]++;
					if(fw[E[u][i].v]>n+2) {
						return 1;
					}
					q.push(E[u][i].v);
					vis[E[u][i].v]=1;
				}
			}
		}
	}
	return 0;
}
int main() {
    double l,r=0;
	scanf("%d%d%d",&n,&s,&t);
	for(int i=1; i<=s; i++) {
		scanf("%d%d%d%d",&o,&A,&B,&K);
		E[A].push_back({B,1.0*K,o});
		r=max(1.0*K,r);
	}
	for(int i=1; i<=t; i++) {
		scanf("%d%d",&C,&X);//c-0==x
		E[C].push_back({0,-log(X),0});//c-0<=x
		E[0].push_back({C,log(X),0});//0<=c-x
	}
	for(int i=0;i<=n;i++){
		E[n+1].push_back({i,0,0});
	}
	if(!check(0)){
		printf("-1");
		return 0;
	}
	l=0;
	while(r-l>1e-6) {
		double mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%lf",r);
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值