题目大意
给出一个长度为N的序列a。
定义
f(i,j)=(i−j)2+g(i,j)2
g(i,j)=∑jk=iak
求最小的
f(i,j)
Data Constraint
N≤105
题解
设
Sum[i]
表示1~i的和。
那么
f(i,j)=(i−j)2+(Sum[j]−Sum[i])2
问题变成:求形如
(i,Sum[i])
点对间的最小距离。
可以分治求解。
时间复杂度:O(NlogN^2)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;
#define N 100000 + 10
typedef long long ll ;
const ll Inf = 1e13 ;
struct Note {
ll x , y ;
Note ( int X = 0 , int Y = 0 ) { x = X , y = Y ; }
} Point[N] , Q[N] ;
int n ;
int a[N] ;
ll ans ;
bool cmpx( Note a , Note b ) { return a.x < b.x || ( a.x == b.x && a.y < b.y ) ; }
bool cmpy( Note a , Note b ) { return a.y < b.y ; }
ll Sqr( ll x ) { return x * x ; }
ll Dis2( Note a , Note b ) {
return Sqr( a.x - b.x ) + Sqr( a.y - b.y ) ;
}
ll DIV( int l , int r ) {
ll ret = Inf ;
if ( l == r ) return ret ;
if ( l + 1 == r ) return Dis2( Point[l] , Point[r] ) ;
int mid = (l + r) / 2 ;
ll d1 = DIV( l , mid ) ;
ll d2 = DIV( mid + 1 , r ) ;
ret = min( d1 , d2 ) ;
double d = sqrt( (double)ret ) ;
int k = 0 ;
for (int i = mid ; i >= l ; i -- ) {
if ( Point[mid].x - Point[i].x > (ll)d ) break ;
Q[++k] = Point[i] ;
}
for (int i = mid + 1 ; i <= r ; i ++ ) {
if ( Point[i].x - Point[mid].x > (ll)d ) break ;
Q[++k] = Point[i] ;
}
sort( Q + 1 , Q + k + 1 , cmpy ) ;
for (int i = 1 ; i < k ; i ++ ) {
for (int j = i + 1 ; j <= k && Q[j].y - Q[i].y <= (ll)d ; j ++ ) {
ret = min( ret , Dis2( Q[i] , Q[j] ) ) ;
}
}
return ret ;
}
int main() {
scanf( "%d" , &n ) ;
ll sum = 0 ;
for (int i = 1 ; i <= n ; i ++ ) {
scanf( "%d" , &a[i] ) ;
sum += a[i] ;
Point[i].x = i ;
Point[i].y = sum ;
}
sort( Point + 1 , Point + n + 1 , cmpx ) ;
printf( "%lld\n" , DIV( 1 , n ) ) ;
return 0 ;
}
以上.