题解 CF429D【Tricky Function】
$\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~

浙公网安备 33010602011771号