标签:二分答案,差分约束
题目
题目描述
今天Scarlet在机房有幸目睹了一场别开生面的OI训练。因为一些奇妙的SPJ,比赛中所有选手的得分都是正实数(甚至没有上限)。
当一位选手A的分数不小于选手B的分数\(k\)(\(k>0\))倍时,我们称选手A“\(k\)倍杀”了选手B,选手B被选手A“\(k\)倍杀”了
更奇妙也更激动人心的是,训练前有不少选手立下了诸如“我没\(k\)倍杀选手X,我就女装”,“选手Y把我\(k\)倍杀,我就女装”的Flag。
知道真相的良心教练Patchouli为了维持机房秩序,放宽了选手们的Flag限制。Patchouli设定了一个正常数\(T\),立下“我没\(k\)倍杀选手X就女装”的选手只要成功\(k-T\)倍杀了选手X,就不需要女装。同样的,立下“选手Y把我\(k\)倍杀我就女装”的选手只要没有成功被选手Y\(k+T\)倍杀,也不需要女装。
提前知道了某些选手分数和具体Flag的Scarlet实在不忍心看到这么一次精彩比赛却没人女装,为了方便和Patchouli交易,Scarlet想要确定最大的实数\(T\)使得赛后一定有选手收Flag女装。
输入输出格式
输入格式
第一行三个整数\(n,s,t\),分别表示机房内选手人数,选手立下的Flag总数和Scarlet已知的选手分数的数量。\(n\)位选手从\(1\)开始编号至\(n\),编号为\(k\)的选手被称为选手\(k\)。
接下来\(s\)行,每行四个整数\(o,A,B,k\)。其中\(o=1\)表示选手A立下了“我没\(k\)倍杀选手B就女装”的Flag,\(o=2\)表示选手A立下了“选手B把我\(k\)倍杀我就女装”的Flag。
接下来\(t\)行,每行两个整数\(C,x\),表示Scarlet已知选手C的分数为\(x\)
输出格式
若存在能保证赛后有选手女装的最大的T,则输出T,只有当输出与答案的绝对误差不超过\(10^{-4}\)时才被视作正确输出。
若不存在,输出”-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
3 2 3
1 2 1 10
2 2 3 6
1 1
2 6
3 9
输出样例#2
3.9999993984
说明
对于30%的数据,\(1\leq n\leq5,1\leq s\leq 2\)
对于另40%的数据,保证\(t=n\)
对于100%的数据,\(1\leq n,s\leq 1000,1\leq A,B,C,t\leq n,1\leq k\leq 10,1\leq x\leq 10^9\)。保证输入中的\(C\)两两不同。
题解
很套路先二分答案
设每个选手的分数为\(X_i\)
为了保证选手A不女装(前提)
如果选手A立下了flag“选手Y把我\(k\)倍杀,我就女装”,那么\(x_A(k+T)\geq x_B\)
如果选手A立下了flag“我没\(k\)倍杀选手X,我就女装”,那么\(x_A>x_B(k-T)\)
之后可以取log套用差分约束模型
然而我的代码并不是标准的SPFA差分约束模板,但比std快不少(逃
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
#define mid ((l+r)/2)
#define eps 1e-15
#define v e[i].to
using namespace std;
inline ll read(){
ll f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//**********head by yjjr**********
const int maxn=1e5;
struct node{ll o,x,y;double z;}p[maxn];
struct edge{int to,next;double w;}e[maxn<<1];
int last[maxn],num=0,cnt=0;bool flag,vis[maxn];
double dis[maxn],b[maxn];ll n,m,s,c,a[maxn];
void insert(int x,int y,double z){e[++cnt]=(edge){y,last[x],z};last[x]=cnt;}
void dfs(ll x,double k){
if(vis[x]){if(k/dis[x]>eps+1)flag=1;return;}
vis[x]=1;dis[x]=k;
reg(x){
dfs(v,k*e[i].w);
if(flag)return;
}
vis[x]=0;
}
int main()
{
n=read(),m=read(),c=read();
rep(i,1,m)p[i]=(node){read()-1,read(),read(),read()};
s=n+1;
rep(i,1,c)a[i]=read(),b[i]=read();
bool OK=0;double l=eps,r=10.0-eps;
while(num<=100){
num++;flag=false;
mem(last,0);mem(vis,0);mem(dis,0);
rep(i,1,c){insert(s,a[i],b[i]);insert(a[i],s,1.0/b[i]);}
rep(i,1,m)
if(!p[i].o)insert(p[i].y,p[i].x,p[i].z-mid);
else insert(p[i].y,p[i].x,1.0/(p[i].z+mid));
dfs(s,1);
if(flag)l=mid,OK=1;else r=mid;
}
if(OK)printf("%.6lf",l);else puts("-1");
return 0;
}