CodeForces 429D Tricky Function

题目大意

给出一个长度为N的序列a。
定义
f(i,j)=(ij)2+g(i,j)2
g(i,j)=jk=iak
求最小的 f(i,j)

Data Constraint
N105

题解

Sum[i] 表示1~i的和。
那么 f(i,j)=(ij)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 ;
}

以上.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值