P4926 [1007]倍杀测量者

题意:

找到一个最大的T,使得类型1的flag只需要达成SA(kT)SBS_A\ge(k-T)*S_B,类型2的flag只需达成SB(k+T)SAS_B\ge(k+T)*S_A即可不用女装的情况下,仍然有人需要女装。

分析:

使用二分 + 差分约束

首先从题意可知,如果有一个T使得不等式有解,则此时无人女装。同样,如果有一个T使得不等式无解,则此时至少有一个人需要女装。故我们只需要用二分进行枚举并用spfa判负环判断不等式有解还是无解即可。

其次对差分约束系统进行分析:

由于精度问题,我们需要把原式转化为log(SA)log(kT)+log(SB)log(S_A)\ge log(k-T)+log(S_B)进行建边即可(另一种类型同理)

所以对于类型1,我们需要从A->B建一条长度为log(kT)-log(k-T)的边。对于类型2,需要从A->B建一条长度为log(k+T)log(k+T)的边。

此外,对于已知成绩的学生,相当于SC=xS_C=x等价于SC=xS0S_C=x*S_0。经过与上述相同步骤的转化,即可从0到学生C建一条log(x)log(x)边,并从学生C到0建一条log(x)-log(x)的边。

同时,由于仍有同学可能无法访问,需要建一条从每个同学到源点0的长度为0的边。

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

#include <bits/stdc++.h>

using namespace std;
#define fast \
ios_base::sync_with_stdio(false); \
cin.tie(NULL);
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-5;
struct node {
int u, v, next;
double w;
int type;
} a[M];
int f[N], cnt;
void add(int u, int v, double w, int type) {
a[++cnt].v = v;
a[cnt].w = w;
a[cnt].type = type;
a[cnt].next = f[u];
f[u] = cnt;
}
int n, s, t;
double dis[N];
int sta[N], Count[N], st[N], top = 0;
bool spfa(double T){
top = 0;
for (int i = 0; i <= n; i++){
dis[i] = 999999999999;
Count[i] = 0;
st[i] = 0;
}
dis[0] = 0;
queue<int> q;
q.push(0);
//sta[++top] = 0;
st[0] = 1;
while(!q.empty()){
//int u = sta[top--];
int u = q.front();
q.pop();
st[u] = 0;
for (int i = f[u]; i; i = a[i].next){
int v = a[i].v;
double w = a[i].w;
if(a[i].type == 1) w = -log2(a[i].w - T);
if(a[i].type == 2) w = log2(a[i].w + T);
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
Count[v] = Count[u] + 1;
if(Count[v] >= n + 2) return true;
if(!st[v]){
st[v] = 1;
//sta[++top] = v;
q.push(v);
}
}
}
}
return false;
}
int main() {
cin >> n >> s >> t;
double l = 0, r = 10;
for (int i = 1; i <= n; i++) add(i, 0, 0, 0);
for (int i = 1; i <= s; i++){
int type, u, v, w;
scanf("%d%d%d%d", &type, &u, &v, &w);
add(u, v, (double)w, type);
}
for (int i = 1; i <= t; i++){
int c, x;
scanf("%d%d",&c, &x);
add(c, 0, -log2(x), 0);
add(0, c, log2(x), 0);
}
if(!spfa(0)) puts("-1");
else{
double ans = 0;
while(fabs(l - r) > eps){
double mid = (l + r) / 2.0;
if(spfa(mid)){
ans = mid;
l = mid;
}else{
r = mid;
}
}
printf("%.6f\n", ans);
}
return 0;
}