题解 P4926 【[1007]倍杀测量者】

xzyxzy

2018-10-20 16:28:40

Solution

# 题意 某地信息组流行女装。 一场考试后,一些骄傲的大佬和一些暴躁的蒟蒻达成约定: 如果某选手不满足以下限制条件,他将会被强迫女装 - $s[A]>s[B]*k_i$ - $s[A]>s[B]*\frac{1}{k_i}$ 其中$s[A]$表示选手A的分数。同时你还已知一些选手的分数 请你求出最大的正实数$T$,使得限制条件变成下面的形式后,仍然有人女装 - $s[A]>s[B]*(k_i-T)$ - $s[A]>s[B]*\frac{1}{(k_i+T)}$ 数据范围:限制数$\le1000$,$1\le k\le10$且为整数,已知选手的分数不超过$10^9$ # 题解 转化题意之后,就可以二分答案T了 对限制条件进行差分约束连边 - 对于$s[A]>s[B]*k_i$,从$B$向$A$连一条权值为$k_i$的边 - 对于$s[A]=x$,默认$s[0]=1$,从$0$向$A$连$x$,从$A$向$0$连$\frac{1}{x}$ 对此图跑乘积最长路即可,如果存在环,则合法 ```cpp #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<queue> using namespace std; const int N=1100; struct flag{int o,a,b,k;}fl[N]; struct edge{int next,to;double w;}a[N<<1]; int n,s,t,c[N],fr[N],head[N],cnt,vis[N]; double dis[N];queue<int> Q; void link(int x,int y,double w){a[++cnt]=(edge){head[x],y,w};head[x]=cnt;} int check(double T) { memset(head,0,sizeof(head)); memset(fr,0,sizeof(fr));cnt=0; while(!Q.empty()) Q.pop(); for(int i=0;i<=n;i++) dis[i]=1,fr[i]=0,vis[i]=1,Q.push(i); for(int i=1;i<=n;i++) if(c[i]) link(i,0,1.0/c[i]),link(0,i,c[i]); for(int i=1;i<=s;i++) { int A=fl[i].a,B=fl[i].b,k=fl[i].k,o=fl[i].o; if(o==1) link(B,A,k-T); else link(B,A,1.0/(k+T)); } while(!Q.empty()) { int x=Q.front(); for(int i=head[x];i;i=a[i].next) { int R=a[i].to; if(dis[R]>=dis[x]*a[i].w) continue; dis[R]=dis[x]*a[i].w;fr[R]=fr[x]+1; if(fr[R]==n+2) return 1; if(!vis[R]) Q.push(R),vis[R]=1; } Q.pop();vis[x]=0; } return 0; } int main() { cin>>n>>s>>t; double l=0,r=1e18,T=-1; for(int i=1;i<=s;i++) { int o,a,b,k;cin>>o>>a>>b>>k; fl[i]=(flag){o,a,b,k}; if(o==1) r=min(r,(double)k-1e-8); } for(int i=1,C,x;i<=t;i++) cin>>C>>x,c[C]=x; while(r-l>1e-8) { double mid=(l+r)/2; check(mid)?l=T=mid:r=mid; } T==-1?puts("-1"):printf("%.10lf\n",T); } ``` 广告:https://www.cnblogs.com/xzyxzy ~~至今有些不明白的是,如果取倒数之后连边跑最短路、或者取对数后再做 会WA。如果有用该方法过了的同学,可以私信我一起讨论QAQ~~ 感谢究极龙骑士:之前不能过的原因是上界有错,而且在连边之前没有判断是否已经合法,以及在跑SPFA时n+1个点应该是n+2长度的最短路才有正环。 现在已经用最短路+取对数AC本题: ```cpp #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<queue> #define float double using namespace std; const int N=1100; struct flag{int o,a,b,k;}fl[N]; struct edge{int next,to,tag;float w;}a[N<<1]; int n,s,t,c[N],fr[N],head[N],cnt,vis[N],gt[N]; float dis[N];queue<int> Q; void link(int x,int y,int tag,float w) {a[++cnt]=(edge){head[x],y,tag,log2(w)};head[x]=cnt;} int check(float T) { memset(head,0,sizeof(head)); memset(fr,0,sizeof(fr));cnt=0; while(!Q.empty()) Q.pop(); for(int i=1;i<=n;i++) if(c[i]) link(i,0,1,c[i]),link(0,i,0,c[i]); for(int i=1;i<=s;i++) { int A=fl[i].a,B=fl[i].b,k=fl[i].k,o=fl[i].o; if(c[A]&&c[B]&&((o==1&&c[A]<c[B]*(k-T))|| (o==2&&c[A]*(k+T)<c[B]))) return 1; if(o==1) link(A,B,1,k-T); else link(A,B,0,k+T); } for(int i=0;i<=n;i++) dis[i]=0,fr[i]=0,Q.push(i),vis[i]=1; while(!Q.empty()) { int x=Q.front(); for(int i=head[x];i;i=a[i].next) { int R=a[i].to; float w=a[i].tag?dis[x]-a[i].w:dis[x]+a[i].w; if(dis[R]<=w&&dis[R]!=-1) continue; dis[R]=w;fr[R]=fr[x]+1; if(fr[R]==n+2) return 1; if(!vis[R]) Q.push(R),vis[R]=1; } Q.pop();vis[x]=0; } return 0; } int main() { cin>>n>>s>>t; float l=0,r=1e18,T=-1; for(int i=1;i<=s;i++) { int o,a,b,k;cin>>o>>a>>b>>k; fl[i]=(flag){o,a,b,k}; if(o==1) r=min(r,(float)k-1e-8); } for(int i=1,C,x;i<=t;i++) cin>>C>>x,c[C]=x; while(r-l>1e-6) { float mid=(l+r)/2.0; check(mid)?l=T=mid:r=mid; } T==-1?puts("-1"):printf("%.10f\n",(double)T); } ``` (题解有更新,烦请管理员再次通过)