题目描述
自从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]表示前缀和)
而选取两个商品作为头和尾的代价为
等价于两点间的距离;
所以问题转化为经典的最近点对距离。
运用分治解决。
时间复杂度为
事实上还有
考虑到选取的两个商品相距不会远;如果太远就会使答案更小。
所以只需考虑区间得大小不会超过个位数级别的即可。
代码
#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;
}
启发
很明显的所有区间模型。直接套分治即可。
但事实上分治也不用,多考虑题目的特质,即可想出水法。