10.7考试总结

10.7考试总结


二分答案专题OwO


T1

【问题描述】
一场地震毁了 Farmer John 的整个农场。他是个有恒心的人,决定
重建农场。在重建了所有 n( 1<=n<=400)块田野后,他意识到还得
修路将它们连起来。完工后,任两个田野间必须有路。
研究了地形后, FJ 认为 m(1<=m<=10000)条双向的道路可能建造。
由于资金短缺,他希望已尽可能省钱的方式完成整个工程。
幸运的是,奶牛们已经成立了针对地震后修建农场道路的工程顾
问公司。奶牛们也很有经济头脑,对没有漂亮利润的工作从不感兴趣。
奶牛们关心可能的利益。他们已经说定了为修路所获的酬金
f(1<=f<=2,000,000,000),并得到一张关于可能的道路、修建每条路的
时 间 ( 以 小 时 计 ) ( 1 <=t<=2,000,000,000 ) 以 及 花 费
(1<=c<=2000,000,000)的列表。在两块田野间可能有多于一条的道路
被列出,所给数据总有可以连通所有田野的修路方案,虽然可能无利
可图。
确定奶牛修路最高的盈利率。
输入文件
第一行三个整数 N, M, F。
2...M+1 行: 每行四个空格隔开的整数: i, j, c,t 描述两块田夜间的一
条道路。
3
输出文件
只包含一个数,保留四位小数,奶牛每个小时可以得到的最大利润,
如果利润非正,输出 0.0000 。
样例输入 ( quake.in):
5 5 100
1 2 20 5
1 3 20 5
1 4 20 5
1 5 20 5
2 3 23 1
样例输出( quake.out):
1.0625
[奶牛选择建最后四条路,总花费 83 时间 16,他们的筹劳是 100,所
以他们在 16 各单位时间内得到利润 100-83: 17/16 = 1.0625。

网上有 并不知道在哪里评测= =
题目要求(frac{F-sum c_i}{sum t_i})的最大值
(x=frac{F-sum c_i}{sum t_i}),然后乱搞得(sum t_i imes x=F-sum c_i)
再乱搞得(F-sum c_i-sum t_i imes x=0)
(f(x)=F-sum c_i-sum t_i imes x)
显然这东西是个递减函数= =
二分(x),然后把边权设成(c_i+t_i imes x),跑一遍最小生成树,把总和与F比一比完事

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "quake"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define db long double
typedef long long ll;
il int gi(){
    rg int x=0;bool flg=0;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
const int maxn=401,maxm=10001;
int n,m,f;
struct edge{int a,b,w,t;db v;}e[maxm];
bool operator < (edge a,edge b){return a.v<b.v;}
int fa[maxn];
il int hd(int i){return fa[i]==i?i:hd(fa[i]);}
il bool check(ll mid){
	rep(i,1,m)e[i].v=mid/3e6*e[i].t+e[i].w;
	int x=1;
	sort(e+1,e+m+1);rep(i,1,n)fa[i]=i;
	db k=f+1e-12;
	rep(i,2,n){
		while(x<=m&&hd(e[x].a)==hd(e[x].b))++x;
		fa[hd(e[x].a)]=hd(e[x].b),k-=e[x].v;
		if(k<0)return 0;
	}return 1;
}
int main(){
	freopen(Fname".in","r",stdin);
	freopen(Fname".out","w",stdout);
	n=gi(),m=gi(),f=gi();
	rep(i,1,m)e[i].a=gi(),e[i].b=gi(),e[i].w=gi(),e[i].t=gi();
	if(!check(0ll)){puts("0.0000");return 0;}
	ll mid,l=0,r=2e15;
	while(l<r){
		mid=(l+r)>>1;
		if(check(mid+1))l=mid+1;
		else r=mid;
	}printf("%.4Lf
",l/(db)3e6);
	return 0;
}

Ps.mdzz卡精度大狗题。。。


T2

http://www.lydsy.com/JudgeOnline/problem.php?id=1816

二分+1
二分一下几副牌,然后要加的joker数量为(sum max(mid-c[i],0))
加的joker最多(min(m,mid))个。判断一下下

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "cards"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il ll gi(){
    rg ll x=0;bool flg=0;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
ll c[52],n,m;
il bool check(const ll&mid){
	ll tot=0;
	rep(i,1,n)tot+=max(0ll,mid-c[i]);
	return tot<=min(m,mid);
}
int main(){
    freopen(Fname".in","r",stdin);
    freopen(Fname".out","w",stdout);
	n=gi(),m=gi();
	ll mid,l=0,r=2e9;
	rep(i,1,n)c[i]=gi();
	while(l<r){
		mid=(l+r)>>1;
		if(check(mid+1))l=mid+1;
		else r=mid;
	}printf("%lld
",l);
    return 0;
}

T3

https://www.luogu.org/problem/show?pid=3199#sub
有向图最小圈。
要求的是(frac{sum C_i}{k})最小值
依然令(x=frac{sum C_i}{k})
(k imes x=sum C_i)
(sum_{i=1}^{k} C_i-k imes x=0)
(sum C_i - x=0)
如果(sum C_i -x <0)的话,图就有负环了= =二分(x),用神搜四把法搞搞。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define Fname "cycle"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0;bool flg=0;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
#define db long double
il db gf(){static db a;scanf("%Lf",&a);return a;}
const int maxn=3010,maxm=10010;
int n,m,s,fir[maxn],dis[maxm],nxt[maxm],id;db w[maxm];
il vd add(int a,int b,db c){nxt[++id]=fir[a],dis[id]=b,fir[a]=id,w[id]=c;}
db dist[maxn];bool flg=0;
bool vis[maxn];
il vd spfa(const int &x){
	vis[x]=1;
	erep(i,x)if(dist[dis[i]]>dist[x]+w[i]){
		dist[dis[i]]=dist[x]+w[i];
		if(flg||vis[dis[i]]){flg=1;break;}
		spfa(dis[i]);
	}
	vis[x]=0;
}
il bool check(ll a){
	rep(i,1,id)w[i]-=a/1e9-(1e-16);
	rep(i,1,n)dist[i]=0,vis[i]=0;
	flg=0;
	rep(i,1,n){
		spfa(i);
		if(flg)break;
	}
	rep(i,1,id)w[i]+=a/1e9-(1e-16);
	return !flg;
}
int __sum;
il vd dfs(const int&x){vis[x]=1,++__sum;erep(i,x)if(!vis[dis[i]])dfs(dis[i]);}
int main(){
	freopen(Fname".in","r",stdin);
	freopen(Fname".out","w",stdout);
	n=gi(),m=gi();
	int a,b;db c;
	while(m--)a=gi(),b=gi(),c=gf(),add(a,b,c);
	ll l=-1e16,r=1e16,mid;
	rep(i,1,n){
		memset(vis,0,sizeof vis);
		__sum=0;dfs(i);
		if(__sum==n){s=i;break;}
	}
	while(l<r){
		mid=((l+r)>>1)+1;
		if(check(mid))l=mid;
		else r=mid-1;
	}
	printf("%.8lf
",l/1e9);
	return 0;
}

STO dsl AK OTZ

原文地址:https://www.cnblogs.com/xzz_233/p/7635727.html