【LuoguP4926】倍杀测量者(LGR-053)-二分答案+差分约束+判正环

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Maxwei_wzj/article/details/83175963

测试地址:倍杀测量者
做法: 本题需要用到二分答案+差分约束+判正环。
对于第一种flag,用不等式表示:如果满足 x A ( k T ) x B x_A\ge (k-T)x_B 就不用女装;对于第二种flag,用不等式表示:如果满足 x A ( k + T ) > x B x_A(k+T)> x_B 就不用女装。显然我们可以二分 T T (因为显然 T T 越大这些条件更容易满足),转化成判定这些条件能不能同时合法的问题,那么使得这些条件同时满足的最小的 T T 就可以近似地看作使得存在一个条件满足的最大的 T T 了。
但是我们发现这些条件很难直接去判断合不合法,这时候我们想到一个判断这种两变量间不等式组合不合法的一个图论模型:差分约束系统,但这个题的条件形式不是差分,这怎么办呢?
我们知道 log ( A B ) = log ( A ) + log ( B ) \log(A\cdot B)=\log(A)+\log(B) ,而且 log ( x ) \log(x) 也是单调增的函数,所以我们萌生一个大胆的想法:将上面的所有条件都取 log \log ,于是上面的条件就变成:
log ( x A ) log ( x B ) log ( k T ) \log(x_A)-\log(x_B)\ge \log(k-T) log ( x A ) log ( x B ) > log ( k + T ) \log(x_A)-\log(x_B)>-\log(k+T)
因为这些变量都是在实数域内的,因此 > > 可以近似地看作 \ge ,这就符合差分约束系统的使用条件了。于是我们把差分约束系统建出来,然后用SPFA算法判正环即可。时间复杂度为 O ( n 2 log C ) O(n^2\log C) log C \log C 表示二分 T T 的复杂度)。
现在还有几个遗留的问题。首先,已知变量怎么处理?我们可以建立一个参照点,把这一点当成相对的 0 0 ,那么 x i = k x_i=k 就等价于 x i 0 k x_i-0\ge k 0 x i k 0-x_i\ge -k 两个条件,在差分约束系统中建边即可。
然后就是源点不确定,建一个超级源点向所有点连边即可。
还有就是判断无解的问题。因为 T T 要是正实数,所以如果 T = 0 T=0 时所有条件就都满足了,那显然就不可能存在 T > 0 T>0 使得存在一个条件不满足了,特判一下即可。
最后注意一下 T T 的二分范围,因为 log ( k T ) \log(k-T) k T 0 k-T\le 0 时没有意义,所以 T T 的最大值应该被设为上述第一种flag中 k k 的最小值。如果没有第一种flag…那上界设到 10 10 就够了(虽然我也不知道为啥就够了)。
以下是本人代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/Maxwei_wzj/article/details/83175963