题意是给定平面内2000给点(都在y轴右边),要选出一些点,和原点组成多边形,求在多边形内的点的点权和除以多边形周长的最大值。
分数规划,二分答案
这样求 ∑w−mid∑disi,j 的最大值就行了
发现答案肯定是个凸多边形
考虑DP,把点按照极角排序,令 fi 为前 i 个点选出一些点的最大值。
那么 fi=max{fj+Query(j,i)−x×dist(i,j)}
其中 Query(i,j) 表示原点 i 和 j 形成的三角形包住的点的点权和, dist 表示距离
Query(i,j) 这个东西预处理一下,就可以 n2 DP了
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=2010;
const double eps=1e-8;
int n;
double f[N];
struct Pt{
int x,y,g,w; double val;
Pt(int _a=0,int _b=0):x(_a),y(_b){}
friend bool operator <(Pt a,Pt b){
return b.val>a.val;
}
friend Pt operator -(Pt a,Pt b){
return Pt(a.x-b.x,a.y-b.y);
}
double len(){
return sqrt(x*x+y*y);
}
}p[N],tmp[N];
inline double ang(Pt a,Pt b){
return acos((a.x*b.x+a.y*b.y)/a.len()/b.len());
}
inline double dist(Pt a,Pt b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int pos[N],b[N],g[N][N];
inline int Query(int x,int n){
int ret=0;
for(;x<=n;x+=x&-x) ret+=b[x];
return ret;
}
inline void Add(int x,int y){
for(;x;x-=x&-x) b[x]+=y;
}
inline bool check(double x){
for(int i=1;i<=n;i++) f[i]=p[i].w-dist(p[i],Pt())*x;
for(int i=2;i<=n;i++)
for(int j=1;jfor(int i=1;i<=n;i++) if(f[i]-x*dist(p[i],Pt())>=0) return true;
return false;
}
inline void Pre(){
for(int i=1;i<=n;i++){
int cnt=0,tot=0;
for(int j=i+1;j<=n;j++){
tmp[++cnt]=p[j];
tmp[cnt].val=ang(p[j]-p[i],p[i]);
tmp[cnt].g=j;
}
sort(tmp+1,tmp+1+cnt);
for(int j=1;j<=cnt;j++){
pos[tmp[j].g]=j; b[j]=0;
}
for(int j=i+1;j<=n;j++){
Add(pos[j],p[j].w);
g[i][j]=Query(pos[j],cnt);
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w),p[i].val=ang(p[i],Pt(0,-1));
sort(p+1,p+1+n);
Pre();
double L=0,R=1e9,mid;
while(R-L>eps){
check(mid=(L+R)/2)?L=mid:R=mid;
}
printf("%.8lf\n",R);
return 0;
}