【JZOJ4770】【NOIP2016提高A组模拟9.9】闭门造车

题目描述

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

输入

第一行一个正整数 N ,表示零件个数。
第二行 N 个正整数, ai 表示第 i 个零件的价格(即性能)。

输出

一个正整数,表示最小花费。

样例输入

5
6 10 9 8 3

样例输出

34

数据范围

对于 30% 的数据, N≤1000。
对于 50% 的数据, N≤10000。
对于 100% 的数据, N≤100000。

解法

考虑到是所有区间问题,可以考虑分治。
设第i个商品映射到坐标轴上的点是(a[i],sum[i]) (sum[i]表示前缀和)
而选取两个商品作为头和尾的代价为(a[i]a[j])2+(sum[i]sum[j])2
等价于两点间的距离;
所以问题转化为经典的最近点对距离。
运用分治解决。
时间复杂度为O(nlogn)


事实上还有O(n)的水法。
考虑到选取的两个商品相距不会远;如果太远就会使答案更小。
所以只需考虑区间得大小不会超过个位数级别的即可。

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#define ll long long
#define ln(x,y) ll(log(x)/log(y))
#define sqr(x) ((x)*(x))
using namespace std;
const char* fin="aP1.in";
const char* fout="aP1.out";
const ll inf=0x7fffffff;
const ll maxn=100007;
ll n,i,j,k,tmp,tmd,ans=-1;
ll a[maxn];
int main(){
    scanf("%d",&n);
    for (i=1;i<=n;i++) scanf("%d",&a[i]);
    for (i=1;i<=n;i++){
        tmp=0;
        for (j=i+1;j<=n && j<=i+2;j++){
            tmp+=a[j];
            if (ans==-1) ans=sqr(tmp)+sqr(a[j]-a[i]);
            else ans=min(ans,sqr(tmp)+sqr(a[j]-a[i]));
        }
    }
    printf("%lld",ans);
    return 0;
}

启发

很明显的所有区间模型。直接套分治即可。
但事实上分治也不用,多考虑题目的特质,即可想出水法。

原文地址:https://www.cnblogs.com/hiweibolu/p/6714898.html