题解 CF429D【Tricky Function】

$\text{Link}$

$\text{upd2021.7.23}$:修改一处笔误及不规范排版。

题意

给出函数 $g$:

int g(int i, int j) {
    int sum = 0;
    for (int k = min(i, j) + 1; k <= max(i, j); k = k + 1)
        sum = sum + a[k];
    return sum;
}

定义函数 $f(i,j)=(i-j)^2+g^2(i,j)$,求 $\min_{1\le i<j\le n}f(i,j)$。

$2\le n\le 10^5,|a_i|\le10^4$

思路

我们分析一下题目中给出的函数 $f(i,j)$(我们设 $1\leqslant i<j\leqslant n,Pre_x=\sum ^x_{i=1}a_i$),即

$$f(i,j)=(j-i)^2+(Pre_j-Pre_i)^2$$

我们发现,两个平方十分像两点间的距离,只是不用根号,于是我们就可以转化为求平面最近点对问题。

其实我们求平面最近点对并不需要一些玄学方法,我们按 $x$ 坐标排序,取 $\displaystyle\min_{i∈[1,n-s],i+1\leqslant j\leqslant i+s}f(i,j)$,再按 $y$ 坐标排序,取 $\displaystyle\min_{i∈[1,n-s],i+1\leqslant j\leqslant i+s}f(i,j)$,在这里,我们取 $s=3$。

此做法虽正确性不严谨,但是不刻意卡也不会出错,原因是如果 $x$ 坐标或者 $y$ 坐标离太远,就算 $y$ 或 $x$ 相同也不是最近的,不刻意卡是可通过的。

都可这么做。

时间复杂度 $O(n\log n+ns)$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
struct node{
    int x,y;
    friend bool operator<(const node &a,const node &b){
        return a.x<b.x;
    }
    friend long long operator-(const node &a,const node &b){
        return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    }
}a[200001];
inline bool cmp(node a,node b){
    return a.y<b.y;
}
long long minn=1e18;
int n;
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        int sss;
        scanf("%lld",&sss);
        a[i].x=i;
        a[i].y=a[i-1].y+sss;
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n&&j<=i+3;j++){
            minn=min(minn,(a[i]-a[j]));
        }
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n&&j<=i+3;j++){
            minn=min(minn,(a[i]-a[j]));
        }
    }
    printf("%lld",minn);
    return 0;
}

再见 qwq~

posted @ 2020-11-16 13:47  ffffyc  阅读(18)  评论(0)    收藏  举报  来源