题链:
http://codeforces.com/problemset/problem/429/D
题解:
分治,最近点对
不难发现g(i,j)=sum[j]-sum[i],
那么f(i,j)=(i-j)²+(sum[j]-sum[i])²
=(i-j)²+(sum[i]-sum[j])²
然后可以把(i,sum[i])看成平面上的点,
那么要求f(i,j)min就转变为了求平面上的最近点对问题。
用分治即可解决。
代码:
#include<bits/stdc++.h> #define MAXN 100005 #define ll long long #define INF 0x3f3f3f3f3f3f3f3fll using namespace std; struct Point{ ll x,y; bool operator < (const Point &rtm) const { return x<rtm.x||(x==rtm.x&&y<rtm.y); } }A[MAXN],B[MAXN]; int N; ll sum[MAXN]; int idx[MAXN]; ll ABS(ll x){return x<0?-x:x;} bool cmpx(const Point &a,const Point &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);} bool cmpy(const Point &a,const Point &b){return a.y<b.y||(a.y==b.y&&a.x<b.x);} ll dis2(Point &a,Point &b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);} void build_index(){ map<Point,int>M; for(int i=1;i<=N;i++) M[A[i]]=i; for(int i=1;i<=N;i++) idx[i]=M[B[i]]; } ll divide(int l,int r){ ll ans=INF; static int tmpidx[MAXN]; static Point tmpB[MAXN]; if(r-l<=3){ for(int i=l;i<=r;i++) for(int j=i+1;j<=r;j++) ans=min(ans,dis2(A[i],A[j])); return ans; } int mid=(l+r)>>1,bl=l,br=mid+1,bnt; for(int i=l;i<=r;i++){ if(idx[i]<=mid) tmpB[bl]=B[i],tmpidx[bl++]=idx[i]; else tmpB[br]=B[i],tmpidx[br++]=idx[i]; } for(int i=l;i<=r;i++) B[i]=tmpB[i],idx[i]=tmpidx[i]; ans=min(ans,divide(l,mid)); ans=min(ans,divide(mid+1,r)); bnt=l; bl=l; br=mid+1; //归并排序 while(bl<=mid&&br<=r){ if(cmpy(B[bl],B[br])) tmpB[bnt++]=B[bl++]; else tmpB[bnt++]=B[br++]; } while(bl<=mid) tmpB[bnt++]=B[bl++]; while(br<=r) tmpB[bnt++]=B[br++]; for(int i=l;i<=r;i++) B[i]=tmpB[i]; bnt=1; for(int i=l;i<=r;i++) if(ABS(B[i].x-A[mid].x)<=ans) tmpB[bnt++]=B[i]; for(int i=1;i<bnt;i++) for(int j=1;j<=6&&i+j<bnt;j++) ans=min(ans,dis2(tmpB[i],tmpB[i+j])); return ans; } int main(){ scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%lld",&sum[i]); sum[i]+=sum[i-1]; A[i]=B[i]=(Point){i,sum[i]}; } sort(A+1,A+N+1,cmpx); sort(B+1,B+N+1,cmpy); build_index(); ll ans=divide(1,N); printf("%lld\n",ans); return 0; }