JZOJ 4770 闭门造车(平面最近点对)

来源:互联网 发布:专业的数控编程软件 编辑:程序博客网 时间:2024/05/15 00:44

题目

自从htn体验了一把飙车的快感,他就下定决心要闭门造车!但是他两手空空怎么造得出车来呢?无奈的他只好来到了汽车零部件商店。
一走进商店,玲琅满目的各式零件看得htn眼花缭乱。但是他很快便反应过来:我只要买一套好的零件就行。首先它们的性能差不能太大,否则汽车的兼容性不好,开着开着就损坏了;其次,当然是越便宜越好了!为了打造一辆顶级跑车,htn陷入了沉思……
现在商店中有 N 件零件,给出这 N 件零件的价格,其性能等于价格。htn要从中购买一套零件,即选取这个序列的一个子串(连续一段)。要求如下:
1、这一套零件个数要大于等于2(这才算一套)。
2、这套零件的性能差为首尾两个零件的性能差(htn觉得每一个都比较性能差实在是太累了)。
3、购买这套零件的价格和为它们各自价格的总和。
4、最终的总花费为 性能差²+价格和²。
5、由于商店最近有优惠活动,所以每一套零件的第一个都是免费的。对此毫无经验的htn只好向经验丰富的你求助了。

n<=100000
时间限制 1s
空间限制 256M

解题思路

很容易想到最小代价可以转化成二维最近点对距离:
设s[i]为1~i号零件的价格和,每种方案的代价就可以转化成两点的欧拉距离的平方。
然后O(n log n)

#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define maxn 100006#define fr(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;struct nod{    int x,y;} d[maxn];bool cmp(nod a,nod b){    return a.x<b.x;}bool cmp2(int a,int b){    return d[a].y<d[b].y;}double sqr(ll x){    return x*x;}ll dist(nod a,nod b){    return sqr(a.x-b.x)+sqr(a.y-b.y);}int i,n,a[maxn];ll s[maxn];ll ans;ll make(int st,int en){    if (st==en) return 1 << 30;    if (st==en-1) return dist(d[st],d[en]);    ll ans=1 << 30;    if (st==en-2)    {        ans=min(ans,make(st,st+1));        ans=min(ans,min(dist(d[st],d[en]),dist(d[st+1],d[en])));        return ans;    }    int i,j,tot=0,mid;    mid=(st+en) >> 1;    ans=min(make(st,mid),make(mid+1,en));    fr(i,st,en)        if (d[i].x>=d[mid].x-sqrt(ans) && d[i].x<=d[mid].x+sqrt(ans))            a[++tot]=i;    sort(a+1,a+tot+1,cmp2);    fr(i,1,tot)        fr(j,i+1,min(tot,i+7))        {            if (d[a[j]].y-d[a[i]].y>=sqrt(ans)) break;            ans=min(ans,dist(d[a[i]],d[a[j]]));        }    return ans;}int main(){    scanf("%d",&n);    fr(i,1,n)     {        scanf("%d",&a[i]),s[i]=s[i-1]+a[i];        d[i].x=a[i],d[i].y=s[i];    }    sort(d+1,d+n+1,cmp);    ans=make(1,n);    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击