倍殺測量者 洛谷p4929
題目描述
今天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;
}