洛谷 P4926 [1007]倍杀测量者

Description

洛谷传送门

Solution

一道差分约束好题。

题目要求我们输出最大的 \(T\) 使得至少有一个人女装。

那么容易想到二分答案

所以这道题就很明显了,二分答案套差分约束,判断是否符合条件。

再来看如何建图。

  1. 对于 \(C_A > C_B * k\),我们从 \(B\) 向 \(A\) 连一条权值为 \(k\) 的边。

  2. 对于已知分数的选手 \(C_i = k\),我们设一个 0 节点,且 \(S_0 = 1\),然后我们从 0 向 \(i\) 连权值为 \(k\) 的边,从 \(i\) 向 0 连权值为 \(\frac {1}{k}\) 的边。

然后跑一遍最长路,判断是否有环。

如果有就符合条件。

注意:这里的最长路是乘法运算

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define eps 1e-8
#define ll long long

using namespace std;

const ll N = 1010;
ll n, s, t;
double l, r;
struct Upd{
	ll op, a, b, k;
}tmp[N];
ll c[N];
struct node{
	ll v, nxt;
	double w;
}edge[N << 1];
ll head[N], tot;
double dis[N];
ll vis[N], cnt[N];
queue <ll> q;

inline void add(ll x, ll y, double z){
	edge[++tot].v = y;
	edge[tot].w = z;
	edge[tot].nxt = head[x];
	head[x] = tot;
}

inline bool spfa(){
	while(!q.empty()){
		ll x = q.front();
		for(ll i = head[x]; i; i = edge[i].nxt){
			ll y = edge[i].v;
			if(dis[y] >= dis[x] * edge[i].w) continue;
			dis[y] = dis[x] * edge[i].w;
			cnt[y] = cnt[x] + 1;
			if(cnt[y] == n + 2) return 1;
			if(!vis[y])  q.push(y), vis[y] = 1;
		}
		q.pop(), vis[x] = 0;
	}
	return 0;
}

inline bool check(double T){
	memset(head, 0, sizeof(head));
	memset(cnt, 0, sizeof(cnt));
	while(!q.empty()) q.pop();
	tot = 0;
	dis[0] = vis[0] = 1;
	q.push(0);
	for(ll i = 1; i <= n; i++){
		dis[i] = vis[i] = 1;
		q.push(i);
		if(c[i]) add(i, 0, 1.0 / c[i]), add(0, i, c[i]);
	}
	for(ll i = 1; i <= s; i++){
		if(tmp[i].op == 1) add(tmp[i].b, tmp[i].a, tmp[i].k - T);
		else add(tmp[i].b, tmp[i].a, 1.0 / (tmp[i].k + T));
	}
	return spfa();
}

signed main(){
	scanf("%lld%lld%lld", &n, &s, &t);
	l = 0, r = 1e18;
	for(ll i = 1; i <= s; i++){
		ll op, a, b, k;
		scanf("%lld%lld%lld%lld", &op, &a, &b, &k);
		tmp[i] = (Upd){op, a, b, k};
		if(op == 1) r = min(r, 1.0 * k);
	}
	for(ll i = 1; i <= t; i++){
		ll p, x;
		scanf("%lld%lld", &p, &x);
		c[p] = x;
	}
	double ans = -1;
	while(r - l > eps){
		double mid = (l + r) / 2;
		if(check(mid)) ans = mid, l = mid;
		else r = mid;	
	}
	if(ans == -1) puts("-1");
	else printf("%.10lf\n", ans);
	return 0;
}

End

上一篇:PAT_A1126#Eulerian Path


下一篇:Eulerian Video Magnification