1. 程式人生 > >【LuoguP4926】倍殺測量者-二分答案+差分約束+判正環

【LuoguP4926】倍殺測量者-二分答案+差分約束+判正環

測試地址:倍殺測量者 做法: 本題需要用到二分答案+差分約束+判正環。 對於第一種flag,用不等式表示:如果滿足xA(kT)xBx_A\ge (k-T)x_B就不用女裝;對於第二種flag,用不等式表示:如果滿足xA(k+T)>xBx_A(k+T)> x_B就不用女裝。顯然我們可以二分TT(因為顯然TT越大這些條件更容易滿足),轉化成判定這些條件能不能同時合法的問題,那麼使得這些條件同時滿足的最小的TT就可以近似地看作使得存在一個條件滿足的最大的TT了。 但是我們發現這些條件很難直接去判斷合不合法,這時候我們想到一個判斷這種兩變數間不等式組合不合法的一個圖論模型:差分約束系統,但這個題的條件形式不是差分,這怎麼辦呢? 我們知道log

(AB)=log(A)+log(B)\log(A\cdot B)=\log(A)+\log(B),而且log(x)\log(x)也是單調增的函式,所以我們萌生一個大膽的想法:將上面的所有條件都取log\log,於是上面的條件就變成: log(xA)log(xB)log(kT)\log(x_A)-\log(x_B)\ge \log(k-T)log(xA)log(xB)>log(k+T)\log(x_A)-\log(x_B)>-\log(k+T)
因為這些變數都是在實數域內的,因此>>可以近似地看作\ge,這就符合差分約束系統的使用條件了。於是我們把差分約束系統建出來,然後用SPFA演算法判正環即可。時間複雜度為O(n2logC)O(n^2\log C)logC\log C表示二分TT的複雜度)。 現在還有幾個遺留的問題。首先,已知變數怎麼處理?我們可以建立一個參照點,把這一點當成相對的00,那麼xi=kx_i=k就等價於xi0kx_i-0\ge k0xik0-x_i\ge -k兩個條件,在差分約束系統中建邊即可。 然後就是源點不確定,建一個超級源點向所有點連邊即可。 還有就是判斷無解的問題。因為TT要是正實數,所以如果T=0T=0時所有條件就都滿足了,那顯然就不可能存在T>0T>0使得存在一個條件不滿足了,特判一下即可。 最後注意一下TT的二分範圍,因為log(kT)\log(k-T)kT0k-T\le 0時沒有意義,所以TT的最大值應該被設為上述第一種flag中kk的最小值。如果沒有第一種flag…那上界設到1010就夠了(雖然我也不知道為啥就夠了)。 以下是本人程式碼:

#include <bits/stdc++.h>
using namespace std;
const double eps=1e-6;
const double inf=1000000000;
int n,s,t;
int o[1010],a[1010],b[1010];
int c[1010];
double k[1010],x[1010];
int first[1010]={0},tot=0;
struct edge
{
	int v,next;
	double w;
}e[20010];
int vis[1010],inque[1010];
double dis[1010];
queue<int> Q;

void insert(int a,int b,double w)
{
	e[++tot].v=b;
	e[tot].next=first[a];
	e[tot].w=w;
	first[a]=tot;
}

bool spfa(int s)
{
	while(!Q.empty()) Q.pop();
	Q.push(s);
	dis[s]=0;
	inque[s]=1;
	while(!Q.empty())
	{
		int v=Q.front();Q.pop();
		vis[v]++;
		inque[v]=0;
		if (vis[v]>(n+2)) return 0;
		for(int i=first[v];i;i=e[i].next)
			if (dis[e[i].v]<dis[v]+e[i].w)
			{
				dis[e[i].v]=dis[v]+e[i].w;
				if (!inque[e[i].v])
				{
					inque[e[i].v]=1;
					Q.push(e[i].v);
				}
			}
	}
	return 1;
}

bool check(double T)
{
	tot=0;
	memset(first,0,sizeof(first));
	
	for(int i=1;i<=s;i++)
	{
		if (o[i]==1) insert(b[i],a[i],log2(k[i]-T));
		else insert(b[i],a[i],-log2(k[i]+T));
	}
	for(int i=1;i<=t;i++)
	{
		insert(n+1,c[i],log2(x[i]));
		insert(c[i],n+1,-log2(x[i]));
	}
	for(int i=1;i<=n+1;i++)
		insert(n+2,i,0.0);
	
	for(int i=1;i<=n+2;i++)
		dis[i]=-inf;
	memset(vis,0,sizeof(vis));
	memset(inque,0,sizeof(inque));
	return spfa(n+2);
}

int main()
{
	double l=0.0,r=10.0;
	
	scanf("%d%d%d",&n,&s,&t);
	for(int i=1;i<=s;i++)
	{
		scanf("%d%d%d%lf",&o[i],&a[i],&b[i],&k[i]);
		if (o[i]==1) r=min(r,k[i]);
	}
	for(int i=1;i<=t;i++)
		scanf("%d%lf",&c[i],&x[i]);
	
	if (check(0)) printf("-1");
	else
	{
		while(r-l>eps)
		{
			double mid=(l+r)/2.0;
			if (check(mid)) r=mid;
			else l=mid;
		}
		printf("%lf",l);
	}
	
	return 0;
}