题目描述
今天Scarlet在机房有幸目睹了一场别开生面的OI训练。因为一些奇妙的SPJ,比赛中所有选手的得分都是正实数(甚至没有上限)。
当一位选手A的分数不小于选手B的分数kk(k>0k>0)倍时,我们称选手A“kk倍杀”了选手B,选手B被选手A“kk倍杀”了
更奇妙也更激动人心的是,训练前有不少选手立下了诸如“我没kk倍杀选手X,我就女装”,“选手Y把我kk倍杀,我就女装”的Flag。
知道真相的良心教练Patchouli为了维持机房秩序,放宽了选手们的Flag限制。Patchouli设定了一个正常数TT,立下“我没kk倍杀选手X就女装”的选手只要成功k-Tk−T倍杀了选手X,就不需要女装。同样的,立下“选手Y把我kk倍杀我就女装”的选手只要没有成功被选手Yk+Tk+T倍杀,也不需要女装。
提前知道了某些选手分数和具体Flag的Scarlet实在不忍心看到这么一次精彩比赛却没人女装,为了方便和Patchouli交易,Scarlet想要确定最大的实数TT使得赛后一定有选手收Flag女装。
输入输出格式
输入格式:
第一行三个整数n,s,tn,s,t,分别表示机房内选手人数,选手立下的Flag总数和Scarlet已知的选手分数的数量。nn位选手从11开始编号至nn,编号为kk的选手被称为选手kk。
接下来ss行,每行四个整数o,A,B,ko,A,B,k。其中o=1o=1表示选手A立下了“我没kk倍杀选手B就女装”的Flag,o=2o=2表示选手A立下了“选手B把我kk倍杀我就女装”的Flag。
接下来tt行,每行两个整数C,xC,x,表示Scarlet已知选手C的分数为xx
输出格式:
若存在能保证赛后有选手女装的最大的T,则输出T,只有当输出与答案的绝对误差不超过10^{-4}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 21≤n≤5,1≤s≤2
对于另40%的数据,保证t=nt=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^91≤n,s≤1000,1≤A,B,C,t≤n,1≤k≤10,1≤x≤109。保证输入中的CC两两不同。
本题正解为差分约束
题目大意:有s个关系,第i个为:
Ai\geq≥(Ki-T)Bi \bigvee⋁Ai(Ki+T)>Bi
要你求出最大的T使得其中至少有一个关系不满足
另外有 T\in∈(0,+\propto∝) \bigwedge⋀ \forall∀ki \Rightarrow⇒ki-T\in∈(0,+\propto∝)
我们看差分约束的式子:
如果 a-b\geq≥c
那么就由b向a连一条权值为c的边
最后再跑最长路,看有没有正权环
对于此题的条件来说,我们考虑两边同时取log!!!
那么原条件: Ai\geq≥(Ki-T)Bi \bigvee⋁Ai(Ki+T)>Bi
就可以转化为: log(Ai)\geq≥log(Ki-T)+log(Bi) \bigvee⋁log(Ai)+log(Ki+T)>log(Bi)
再然后: log(Ai)-log(Bi)\geq≥log(Ki-T) \bigvee⋁log(Ai)-log(Bi)>-log(Ki+T)
另外我们观察到k很小,k\in∈[1,10],则T的范围也很小,可以二分T来求解
然后就可以愉快的 二分+差分约束 啦!
再说几个细节:
1.我们注意到可能一些人的分数是已知的,此时我们建一个虚点 n+1
依题意:若有(C,x),则:
addedge(n+1,C,x); addedge(C,n+1,-x)
这是一种差分约束中很经典的维护已知量的方法,它可以确保各个已知点之间的相对关系,其实差分约束维护的就是一个相对关系
2.我们注意到 log(Ai)-log(Bi)>-log(Ki+T)
其实并不满足 a-b\geq≥c的形式,但我们为什么还可以用它呢?
其实题目中有说近似值的事情
因为与真实值相差不超过10^-4即可,所以我们可以做这样的近似
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=5005;
int n,s,t;
double dis[MAXN];
int vis[MAXN],tim[MAXN];
struct Edge{
int v,nxt,flag;
double w,k;
}e[MAXN<<1];
int h[MAXN],tot;
inline void add(int u,int v,double w,int flag,double k)
{
e[tot].v=v;
e[tot].nxt=h[u];
e[tot].w=w;
e[tot].flag=flag;
e[tot].k=k;
h[u]=tot++;
}
inline bool SPFA(double ans)
{
int i;
queue<int> q;
memset(vis,0,sizeof(vis));
memset(tim,0,sizeof(tim));
f(i,1,n+2) dis[i]=-1e9;
// cout<<dis[1]<<"GG";
vis[n+2]=1;
tim[n+2]++;
dis[n+2]=0;
q.push(n+2);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(i=h[u];~i;i=e[i].nxt){
int v=e[i].v;
double w=e[i].w;
if(e[i].flag==1) w=log2(e[i].k-ans);
else if(e[i].flag==2) w=-log2(e[i].k+ans);
if(dis[v]<dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
vis[v]=1;
tim[v]++;
q.push(v);
if(tim[v]>n) return false;
}
}
}
}
return true;
}
int main()
{
ios::sync_with_stdio(false);
memset(h,-1,sizeof(h));
int i,j;
int flag,u,v;
double x;
double l=0,r=1000,k;
cin>>n>>s>>t;
f(i,1,s){
cin>>flag>>u>>v>>k;
add(v,u,0,flag,k);
if(flag==1) r=min(r,k);
}
f(i,1,t){
cin>>u>>x;
add(n+1,u,log2(x),0,0);
add(u,n+1,-log2(x),0,0);
}
f(i,1,n+1){
add(n+2,i,0,0,0);
}
if(SPFA(0)){
cout<<-1<<endl;
return 0;
}
while(r-l>1e-5){
double mid=(l+r)/2;
if(SPFA(mid)) r=mid;
else l=mid;
}
cout<<l<<endl;
return 0;
}