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_i\cdot dist(a_i,a))\)最大,其中\(dist(a_i,a)=min(2\pi-|a-a_i|,|a-a_i|)\)

\(1\le n\le 10^5,0 < t\le 1000,0\le s\le 100,0\le a\le 2\pi\)

分析

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

img

对于每一段看做\(y=s\cdot 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\n",ans);
	return 0;
}
posted @ 2020-12-21 22:26  xyq0220  阅读(126)  评论(0编辑  收藏  举报