1. 程式人生 > >倍殺測量者 洛谷p4929

倍殺測量者 洛谷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;
}