解析:
可以转换成求平面最近点对的问题,(i,sum[i]),i为下标,sum[i]为i的前缀和
这里有一个讲解平面最近点对问题的博客点击打开链接
还有证明查找复杂度为常数6的,虽然我看不懂点击打开链接
普通版:
#include <bits/stdc++.h>
using namespace std;
typedef long long int lli;
const int MAXN = 1e5+100;
#define INF 5223372036854775807
typedef struct point
{
lli x;
lli y;
}point;
point aa[MAXN];
point temp[MAXN];
int cnt;
bool cmp1(point a,point b)
{
if(a.x==b.x) return a.y<b.y;
else
return a.x<b.x;
}
bool cmp2(point a,point b)
{
return a.y<b.y;
}
inline lli caldis(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
lli solve(int l,int r)
{
if(l>=r) return INF;
if(l+1==r)
{
return caldis(aa[l],aa[r]);
}
if(r-l+1==3)
{
lli ans1=caldis(aa[l],aa[l+1]);
lli ans2=caldis(aa[l+1],aa[r]);
lli ans3=caldis(aa[l],aa[r]);
lli ans=min(ans1,ans2);
ans=min(ans,ans3);
return ans;
}
int mid=(l+r)>>1;
lli ans=min(solve(l,mid),solve(mid+1,r));
cnt=0;
for(int i=l;i<=r;i++)
{
if(llabs(aa[i].x-aa[mid].x)<ans)
{
temp[cnt]=point{aa[i].x,aa[i].y};
cnt++;
}
}
sort(temp,temp+cnt,cmp2);
for(int i=0;i<cnt;i++)
{
for(int j=i+1;j<cnt&&j<=i+6;j++) //!!!这里必须加j<=i+6不然会T
{
if(temp[j].y-temp[i].y>=ans) break;
ans=min(ans,caldis(temp[i],temp[j]));
}
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
aa[0].x=aa[0].y=0;
for(int i=1;i<=n;i++)
{
lli tmp;
scanf("%lld",&tmp);
aa[i].y=aa[i-1].y+tmp;
aa[i].x=i;
}
sort(aa+1,aa+1+n,cmp1);
lli ans=solve(1,n);
printf("%lld\n",ans);
}
指针版
#include <bits/stdc++.h>
using namespace std;
typedef long long int lli;
const int MAXN = 1e5+100;
#define INF 5223372036854775807
typedef struct point
{
lli x;
lli y;
}point;
point aa[MAXN];
point* px[MAXN];
point* temp[MAXN];
int cnt;
bool cmp2(point *a,point *b)
{
return a->y<b->y;
}
inline lli caldis(point *a,point *b)
{
return (a->x-b->x)*(a->x-b->x)+(a->y-b->y)*(a->y-b->y);
}
lli solve(int l,int r)
{
if(l>=r) return INF;
if(l+1==r)
{
return caldis(px[l],px[r]);
}
if(r-l+1==3)
{
lli ans1=caldis(px[l],px[l+1]);
lli ans2=caldis(px[l+1],px[r]);
lli ans3=caldis(px[l],px[r]);
lli ans=min(ans1,ans2);
ans=min(ans,ans3);
return ans;
}
int mid=(l+r)>>1;
lli ans=min(solve(l,mid),solve(mid+1,r));
cnt=0;
for(int i=l;i<=r;i++)
{
if(px[i]->x>=px[mid]->x-ans&&px[i]->x<=px[mid]->x+ans)
{
temp[cnt]=px[i]; //主要是这里不同
cnt++;
}
}
sort(temp,temp+cnt,cmp2);
for(int i=0;i<cnt;i++)
{
for(int j=i+1;j<cnt&&j<=i+6;j++)
{
//if(temp[j].y-temp[i].y>=ans) break;
if(temp[j]->y-temp[i]->y>=ans) break;
ans=min(ans,caldis(temp[i],temp[j]));
}
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
aa[0].x=aa[0].y=0;
px[0]=&aa[0];
for(int i=1;i<=n;i++)
{
lli tmp;
scanf("%lld",&tmp);
aa[i].y=aa[i-1].y+tmp;
aa[i].x=i;
px[i]=&aa[i];
}
//sort(px+1,px+1+n,cmp1);
lli ans=solve(1,n);
printf("%lld\n",ans);
}
数组版(空间需要最小)
#include <bits/stdc++.h>
using namespace std;
typedef long long int lli;
const int MAXN = 1e5+100;
#define INF 5223372036854775807
typedef struct point
{
lli x;
lli y;
}point;
point aa[MAXN];
int temp[MAXN];
int cnt;
bool cmp1(point a,point b)
{
if(a.x==b.x) return a.y<b.y;
else
return a.x<b.x;
}
/*bool cmp2(point a,point b)
{
return a.y<b.y;
}*/
bool cmp2(int i,int j)
{
return aa[i].y<aa[j].y;
}
lli caldis(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
lli solve(int l,int r)
{
if(l>=r) return INF;
if(l+1==r)
{
return caldis(aa[l],aa[r]);
}
if(r-l+1==3)
{
lli ans1=caldis(aa[l],aa[l+1]);
lli ans2=caldis(aa[l+1],aa[r]);
lli ans3=caldis(aa[l],aa[r]);
lli ans=min(ans1,ans2);
ans=min(ans,ans3);
return ans;
}
int mid=(l+r)>>1;
lli ans=min(solve(l,mid),solve(mid+1,r));
cnt=0;
for(int i=l;i<=r;i++)
{
if(llabs(aa[i].x-aa[mid].x)<ans)
{
temp[cnt]=i; //这里不同
cnt++;
}
}
sort(temp,temp+cnt,cmp2);
for(int i=0;i<cnt;i++)
{
for(int j=i+1;j<cnt&&j<=i+6;j++)
{
//if(temp[j].y-temp[i].y>=ans) break;
if(aa[temp[j]].y-aa[temp[i]].y>=ans) break;
ans=min(ans,caldis(aa[temp[i]],aa[temp[j]]));
}
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
aa[0].x=aa[0].y=0;
for(int i=1;i<=n;i++)
{
lli tmp;
scanf("%lld",&tmp);
aa[i].y=aa[i-1].y+tmp;
aa[i].x=i;
}
sort(aa+1,aa+1+n,cmp1);
lli ans=solve(1,n);
printf("%lld\n",ans);
}