记$b_{i}=a_{i+1}-a_{i}$,不难发现对$i$操作即是交换$b_{i-1}$和$b_{i}$,若干次操作也即对$b_{i}$重新排列
实际上,方差也即$\min_{x}\frac{1}{n}\sum_{i=1}^{n}(a_{i}-x)^{2}$(展开后可得$x=\frac{1}{n}\sum_{i=1}^{n}a_{i}$时取到最小),那么不妨先确定$x$,并考虑$b_{i}$前缀和第一处$>x$的位置,显然其之前单调递减、其之后单调递增(均不严格)
再忽略$x$,即存在一个位置,使得其之前单调递减、其之后单调递增(均不严格)
换言之,也可以看作将$b_{i}$(从小到大)排序后,不断在当前的两侧插入
进一步的,$n^{2}$倍的方差展开后又即$n\sum_{i=1}^{n}a_{i}^{2}-(\sum_{i=1}^{n}a_{i})^{2}$,那么即可dp
具体的,令$f_{i,s}$表示插入到$b_{i}$时,当前$\sum a_{i}=s$的最小$\sum a_{i}^{2}$,对$b_{i}$插入的位置分类转移,即得
$$
f_{i,s}=\min(f_{i-1,s-\sum_{j=1}^{i}b_{j}}+(\sum_{j=1}^{i}b_{j})^{2},f_{i-1,s-i\cdot b_{i}}+2(s-i\cdot b_{i})b_{i}+i\cdot b_{i}^{2})
$$
记$m=a_{n}$,显然$s\le nm$,那么时间复杂度为$o(n^{2}m)$,空间复杂度(对$i$滚动)为$o(nm)$,可以通过
另外,对于$n>10^{4}$的测试点,至多只有$m$个非0的$b_{i}$,而都是0显然插入的位置并没有影响,预先插入即可,时间复杂度降为$o(nm^{2})$,也可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define ll long long 5 int n,s,a[N],b[N],f[N]; 6 ll ans; 7 int main(){ 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 10 for(int i=1;i<n;i++)b[i]=a[i+1]-a[i]; 11 sort(b+1,b+n); 12 for(int i=1;i<n;i++)a[i]=a[i-1]+b[i]; 13 memset(f,0x3f,sizeof(f)); 14 f[0]=0; 15 for(int i=1;i<n;i++){ 16 if (!b[i])continue; 17 s+=i*b[i]; 18 for(int j=s;j>=0;j--){ 19 f[j]=1e9; 20 if (j>=a[i])f[j]=min(f[j],f[j-a[i]]+a[i]*a[i]); 21 if (j>=i*b[i])f[j]=min(f[j],f[j-i*b[i]]+2*(j-i*b[i])*b[i]+i*b[i]*b[i]); 22 } 23 } 24 ans=1e18; 25 for(int i=0;i<=s;i++)ans=min(ans,(ll)n*f[i]-(ll)i*i); 26 printf("%lld\n",ans); 27 return 0; 28 }