luogu CF639E Bear and Paradox |二分+贪心

题意翻译

\(n\) 个问题,第 \(i\) 个问题的初始得分为 \(p_i\)​,所花费的时间为 \(t_i\)​。
\(T = \sum_{i=1}^n t_i\),你可以按照某个顺序恰好花费 \(T\) 时间完成所有问题。
若你在时刻 \(x\) 完成了问题 \(i\),你可以得到 \(p_i \cdot (1 - \frac{cx}T)\) 的得分,其中 \(c\) 是一个 \([0,1]\) 的实数。
对于每个 \(c\),都存在至少一个可以使得分最大的最佳做题顺序。
对于一个做题顺序,若出现了两个问题 \(i,j\) 满足 \(p_i < p_j\)​ 但 \(i\) 的得分严格大于 \(j\) 的得分,则认为这种做题顺序存在悖论。
你需要求出最大的 \(c\),使得这个 \(c\) 对应的任意最佳做题顺序都不存在悖论。
\(n \le 1.5 \times 10^5\)\(p_i,t_i \le 10^8\),答案精度误差 \(\le 10^{-6}\)


用的是普及组难度的算法

写的是省选难度的题...


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define db double
#define int long long
const int N=2e5+5;
const db eps=1e-12;
int n,T;
struct node{
	int a,t,sum,tmin,tmax;
}e[N];
inline bool cmp(node x,node y){
	return x.t*y.a<x.a*y.t;
}
inline bool Cmp(node x,node y){return x.a<y.a;}
bool check(db x){
	db mx=0,tmx=0;
	for(int i=1;i<=n;i++){
		if(e[i].a!=e[i-1].a)mx=tmx;
		if((1-x*e[i].tmax/T)*e[i].a<mx)return 0;
		tmx=max(tmx,(1-x*e[i].tmin/T)*e[i].a);
	}
	return 1;
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&e[i].a);
	for(int i=1;i<=n;i++)scanf("%lld",&e[i].t),T+=e[i].t;
	sort(e+1,e+1+n,cmp);
	for(int i=1;i<=n;i++)e[i].sum=e[i-1].sum+e[i].t;
	for(int l=1,r;l<=n;l=r+1){
		r=l;
		while(r<n&&e[l].t*e[r+1].a==e[l].a*e[r+1].t)r++;
		for(int k=l;k<=r;k++)
		e[k].tmin=e[l-1].sum+e[k].t,e[k].tmax=e[r].sum;
	}
	sort(e+1,e+1+n,Cmp);
	db l=0,r=1,mid;
	while(r-l>eps)check(mid=(l+r)/2)?l=mid:r=mid;
	printf("%.10lf\n",l);
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12989235.html