gym102433 J-Interstellar Travel 计算贡献

gym102433 J-Interstellar Travel

题意

给定(n)个实数三元组((t_i,s_i,a_i)),让你选定一个(a)使得(sum_{i=1}^{n}max(0,t_i-s_icdot dist(a_i,a)))最大,其中(dist(a_i,a)=min(2pi-|a-a_i|,|a-a_i|))

(1le nle 10^5,0 < tle 1000,0le sle 100,0le ale 2pi)

分析

对于每个三元组可以分成四段线性函数

img

对于每一段看做(y=scdot a+t),那么我们只需要将每一段的端点和斜率保存起来,最大值一定在某个端点处取得,按端点排下序,对于排序后的相邻的端点之间计算一下贡献取最大值即可。

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<double,double>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const double pi=acos(-1);
const int mod=1e9+7;
const int N=1e5+10;
const int inf=1e9;
int n;
vector<pii>q;
double s,t,a;
double calc(double x){
	return t-s*(min(2*pi-abs(a-x),abs(a-x)));
}
void add(double l,double r,double pa,double s){
	l=max(l,0.0);
	r=min(r,2*pi);
	if(l>r) return;
	double vl=calc(l),vr=calc(r);
	if(vl<=0&&vr<=0) return;
	if(vl>=0&&vr>=0){
		q.pb(mp(l,s));
		q.pb(mp(r,-s));
	}else if(vl>=0){
		double x=-t/s+pa;
		q.pb(mp(l,s));
		q.pb(mp(x,-s));
	}else if(vr>=0){
		double x=-t/s+pa;
		q.pb(mp(x,s));
		q.pb(mp(r,-s));
	}
}
int main(){
	cin>>n;
	double ret=0;
	rep(i,1,n){
		scanf("%lf%lf%lf",&t,&s,&a);
		ret+=max(0.0,calc(0));
		add(a-2*pi,a-pi,a-2*pi,-s);
		add(a-pi,a,a,s);
		add(a,a+pi,a,-s);
		add(a+pi,a+2*pi,2*pi+a,s);
	}
	sort(q.begin(), q.end());
	double pr=0,k=0,ans=ret;
	for(pii x:q){
		ret+=k*(x.fi-pr);
		k+=x.se;
		pr=x.fi;
		ans=max(ans,ret);
	}
	printf("%.6f
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/xyq0220/p/14170469.html