P4926题解
题目分析
题中所述,一个选手不需要女装的条件为「A 成功
令
由于需要有选手女装,我们需要找到最大的
不过,我们在跑差分约束之前可以先把不等式两边同时取 log,将其变为加减法。两个不等式分别转换为
实现
连边
我们需要储存边的种类、选手得分(若已知)、倍杀中的 k,在差分约束中根据边的种类计算出边权。
两种 flag 所对应的边权即为两个不等式的右项。若没有发生倍杀(即因为已知得分连边),直接将边权定为选手得分。
已知得分
我们再创造一个超级原点,将已知得分的选手与这个点连边(两条,一正一负,同上文所述不等式)。预先将其进行
有无解
若差分约束中出现负环说明此不等式组无解,符合题目要求。将二分中的 l=mid。否则将 r=mid。
若
具体实现
(代码中注释应该很详细了,有注释版本正好一百行。)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int w=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=w*10+ch-48;
ch=getchar();
}
return w*f;
}
#define MAXN 1005
int n,s,t;
double l,r=10.0;
struct node{
int v,nxt;
int op;//边类型
double w,k;//已知得分,倍杀
}e[MAXN*4];
int cnt=0,head[MAXN];
void build(int op,int u,int v,double w,double k){
e[++cnt].op=op,e[cnt].v=v;
e[cnt].w=w,e[cnt].k=k;
e[cnt].nxt=head[u],head[u]=cnt;
}
//建图
//五个参数分别为 边的类型(倍杀还是被倍杀),边的起点,边的终点
//选手得分(若已知,否则为0),倍杀的 k
double dis[MAXN];
int inq[MAXN],c[MAXN];
bool spfa(double t){
queue<int>q;
for(int i=0;i<=n;i++)dis[i]=-1e9,c[i]=0,inq[i]=0;
//记得清空数组
dis[n+1]=0,inq[n+1]=1,c[n+1]++;
q.push(n+1);
while(!q.empty()){
int u=q.front();
q.pop();
inq[u]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v;
double w=e[i].w;//选手已知的得分
if(e[i].op==1)w=log2(e[i].k-t);//若为第一种 flag
if(e[i].op==2)w=-log2(e[i].k+t);//第二种 flag
if(dis[v]<dis[u]+w){//正常的跑差分约束
dis[v]=dis[u]+w;
if(!inq[v]){
inq[v]=1,c[v]++;
q.push(v);
if(c[v]>=n+1)return 0;//不等式组无解
//由于有两个超级原点,一个点入队大于等于 n+1 次才可判断无解
}
}
}
}
return 1;//不等式组有解
}
int main(){
n=read(),s=read(),t=read();
for(int i=1;i<=s;i++){
int op=read(),a=read(),b=read(),k=read();
build(op,b,a,0,k);//倍杀
if(op==1)r=(double)fmin(r,(double)k);//二分的上界
}
for(int i=1;i<=t;i++){//已知选手得分
int c=read();
double x=(double)read();
build(0,0,c,log2(x),0);
build(0,c,0,-log2(x),0);
//连两条边到超级原点
}
for(int i=0;i<=n;i++)build(0,n+1,i,0,0);
//另一个超级原点保证图的连通
if(spfa(0)){
printf("-1");
return 0;
}//T=0 时仍有解,说明题目无解
while(r-l>1e-5){//由于精度要求不高,无需使用相减判断
double mid=(r+l)/2.0;
if(spfa(mid))r=mid;
else l=mid;
}//二分找到答案
printf("%lf",l);
return 0;
}
后记
注意事项
-
一些数据需要用浮点数存。
-
由于差分约束中边权可能为负,
dis数组需要初始化为一个极小的数(如1e9 )。 -
跑
spfa时注意清空数组。
后记的后记
若发现错误请私信我(毕竟我太菜了,难免出错)。
这道题我断断续续调了差不多一个多月,算是第一道紫题(也是第一篇紫题题解)。