[luogu7962]方差

记$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 } 
View Code

 

posted @ 2021-11-30 20:46  PYWBKTDA  阅读(80)  评论(0编辑  收藏  举报