[NOIP2021] 方差

链接

鉴于 \(luogu\) 经常似,这里把 \(Markdown\) 粘过来了

题目

[NOIP2021] 方差

题目描述

给定长度为 \(n\) 的非严格递增正整数数列 \(1 \le a_1 \le a_2 \le \cdots \le a_n\)。每次可以进行的操作是:任意选择一个正整数 \(1 < i < n\),将 \(a_i\) 变为 \(a_{i - 1} + a_{i + 1} - a_i\)。求在若干次操作之后,该数列的方差最小值是多少。请输出最小值乘以 \(n^2\) 的结果。

其中方差的定义为:数列中每个数与平均值的差的平方的平均值。更形式化地说,方差的定义为 \(D = \frac{1}{n} \sum_{i = 1}^{n} {(a_i - \bar a)}^2\),其中 \(\bar a = \frac{1}{n} \sum_{i = 1}^{n} a_i\)

输入格式

输入的第一行包含一个正整数 \(n\),保证 \(n \le {10}^4\)

输入的第二行有 \(n\) 个正整数,其中第 \(i\) 个数字表示 \(a_i\) 的值。数据保证 \(1 \le a_1 \le a_2 \le \cdots \le a_n\)

输出格式

输出仅一行,包含一个非负整数,表示你所求的方差的最小值的 \(n^2\) 倍。

样例 #1

样例输入 #1

4
1 2 4 6

样例输出 #1

52

提示

【样例解释 #1】

对于 \((a_1, a_2, a_3, a_4) = (1, 2, 4, 6)\),第一次操作得到的数列有 \((1, 3, 4, 6)\),第二次操作得到的新的数列有 \((1, 3, 5, 6)\)。之后无法得到新的数列。

对于 \((a_1, a_2, a_3, a_4) = (1, 2, 4, 6)\),平均值为 \(\frac{13}{4}\),方差为 \(\frac{1}{4}({(1 - \frac{13}{4})}^2 + {(2 - \frac{13}{4})}^2 + {(4 - \frac{13}{4})}^2 + {(6 - \frac{13}{4})}^2) = \frac{59}{16}\)

对于 \((a_1, a_2, a_3, a_4) = (1, 3, 4, 6)\),平均值为 \(\frac{7}{2}\),方差为 \(\frac{1}{4} ({(1 - \frac{7}{2})}^2 + {(3 - \frac{7}{2})}^2 + {(4 - \frac{7}{2})}^2 + {(6 - \frac{7}{2})}^2) = \frac{13}{4}\)

对于 \((a_1, a_2, a_3, a_4) = (1, 3, 5, 6)\),平均值为 \(\frac{15}{4}\),方差为 \(\frac{1}{4} ({(1 - \frac{15}{4})}^2 + {(3 - \frac{15}{4})}^2 + {(5 - \frac{15}{4})}^2 + {(6 - \frac{15}{4})}^2) = \frac{59}{16}\)

【数据范围】

测试点编号 \(n \le\) \(a_i \le\)
\(1 \sim 3\) \(4\) \(10\)
\(4 \sim 5\) \(10\) \(40\)
\(6 \sim 8\) \(15\) \(20\)
\(9 \sim 12\) \(20\) \(300\)
\(13 \sim 15\) \(50\) \(70\)
\(16 \sim 18\) \(100\) \(40\)
\(19 \sim 22\) \(400\) \(600\)
\(23 \sim 25\) \({10}^4\) \(50\)

对于所有的数据,保证 \(1 \le n \le {10}^4\)\(1 \le a_i \le 600\)

历时一天半,共八届奥赛课加两节数学自习的努力,终于给他 \(A\) 了,下面简单回顾一下我这悲苦的历程

题目一开始是没什么思路的,但入手点一定得在操作上找,然后就设一个 \(a_1,a_2,a_3,a_4\) 开始自己胡乱手模

然后我就惊奇的发现,只模这个数是没什么作用的(因为我半个小时后什么也没得出来),然后就不看这个数了,开始

看俩数操作后的关系,就做了个差,然后。。就发现了一个惊奇的性质:操作一个数 \(a_i\) 相当于把 \(a\) 的查分数组 \(x\) 中的

\(x_{i-1}\)\(x_{i}\) 互换位置

那现在问题就转化成了找出一个 \(x\) 的排列使方差最小,然后就开始推式子了。。。

\(a_i=a_1+\sum_{j=1}^{i-1} \limits x_j\) , \(\bar a=a_1+\frac{1}{n}\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j\)

\[n^2D = n\sum_{i = 1}^{n} {(a_i - \bar a)}^2 \]

\[= n\sum_{i = 1}^{n} {(a_1+\sum_{j=1}^{i-1} \limits x_j -a_1-\frac{1}{n}\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j)}^2 \]

\[= n\sum_{i = 1}^{n} {\left[(\sum_{j=1}^{i-1} \limits x_j)^2-\frac{2}{n}\sum_{j=1}^{i-1} \limits x_j\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j+\frac{1}{n^2}(\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j)^2\right]} \]

\[=\sum_{i = 1}^{n} {\left[n(\sum_{j=1}^{i-1} \limits x_j)^2-2\sum_{j=1}^{i-1} \limits x_j\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j+\frac{1}{n}(\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j)^2\right]} \]

\[=n\sum_{i = 1}^{n}(\sum_{j=1}^{i-1} \limits x_j)^2-2\sum_{i = 1}^{n}\sum_{j=1}^{i-1} \limits x_j\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j+\frac{1}{n}\sum_{i = 1}^{n}(\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j)^2 \]

\[=n\sum_{i = 1}^{n}(\sum_{j=1}^{i-1} \limits x_j)^2-(\sum_{i=1}^{n}\limits\sum_{j=1}^{i-1}\limits x_j)^2 \]

\[=n\sum_{i = 1}^{n-1}(\sum_{j=1}^{i} \limits x_j)^2-(\sum_{i=1}^{n-1}\limits\sum_{j=1}^{i}\limits x_j)^2 \]

这就是我们答案的初始式子了,但我们不知道 \(x\) 序列的排列方式,所以。。。继续推

\[n\sum_{i = 1}^{n-1}(\sum_{j=1}^{i} \limits x_j)^2-(\sum_{i=1}^{n-1}\limits\sum_{j=1}^{i}\limits x_j)^2 \]

\[=n\sum_{i = 1}^{n-1}\sum_{j=1}^{i} \limits\sum_{k=1}^{i} \limits x_j*x_k-(\sum_{i=1}^{n-1}\limits x_i*(n-i))^2 \]

\[=n\sum_{i = 1}^{n-1}\sum_{j=1}^{n-1} \limits x_i*x_j*(n-\max(i,j))-\sum_{i=1}^{n-1}\limits \sum_{j=1}^{n-1}\limits x_i*x_j*(n-i)*(n-j) \]

\[=\sum_{i = 1}^{n-1}\sum_{j=1}^{n-1} \limits x_i*x_j*\left[n*(n-\max(i,j))-(n-i)*(n-j)\right] \]

\[=\sum_{i = 1}^{n-1}\sum_{j=1}^{n-1} \limits x_i*x_j*\left[n^2-n*\max(i,j)-n^2+(i+j)*n-i*j \right] \]

\[=\sum_{i = 1}^{n-1}\sum_{j=1}^{n-1} \limits x_i*x_j*\left[(i+j)*n-n*\max(i,j)-i*j \right] \]

\[=\sum_{i = 1}^{n-1}\sum_{j=1}^{n-1} \limits x_i*x_j*\left[n*\min(i,j)-i*j \right] \]

我们发现这个 \(min\) 不太好处理,但是我们容易推出 \(\sum_{i = 1}^{n-1}\limits \sum_{j=1}^{n-1} \limits x_i*x_j=2*\sum_{i = 1}^{n-1}\limits \sum_{j=1}^{i-1} \limits x_i*x_j+\sum_{i=1}^{n-1}\limits {x_i}^2\)

所以原式可化为

\[=\sum_{i=1}^{n-1}{x_i}^2*(n-i)*i+2*\sum_{i = 1}^{n-1}\sum_{j=1}^{i-1} \limits x_i*x_j*(n-i)*j \]

观察左边的式子发现,当中间部分的 \(x\) 较小时整体较小,这时我们看右边式子,列一下 \(n=7\) 时的矩阵

( i ,j ) i=2 i=3 i=4 i=5 i=6
\(j=5\) \((6,5)\)
\(j=4\) \((5,4)\) \((6,4)\)
\(j=3\) \((4,3)\) \((5,3)\) \((6,3)\)
\(j=2\) \((3,2)\) \((4,2)\) \((5,2)\) \((6,2)\)
\(j=1\) \((2,1)\) \((3,1)\) \((4,1)\) \((5,1)\) \((6,1)\)

我们同时列一下其对应的系数

( i ,j ) i=2 i=3 i=4 i=5 i=6
\(j=5\) \(5\)
\(j=4\) \(8\) \(4\)
\(j=3\) \(9\) \(6\) \(3\)
\(j=2\) \(8\) \(6\) \(4\) \(2\)
\(j=1\) \(5\) \(4\) \(3\) \(2\) \(1\)

我们惊奇的发现,对于右面的式子,也是当中间 \(x\) 的值小时,整体值较小

所以我们就得到了:当 \(x\) 承单谷排列时,使答案最小

但我们又发现一个问题,我们只知道单谷排列,但并不知道“谷”在哪,所以我们就应该 \(DP\)

考虑我们初始的式子\(n\sum_{i = 1}^{n-1}\limits (\sum_{j=1}^{i} \limits x_j)^2-(\sum_{i=1}^{n-1}\limits\sum_{j=1}^{i}\limits x_j)^2\)

我们想让整体最小,就是想让\(\sum_{i = 1}^{n-1}\limits (\sum_{j=1}^{i} \limits x_j)^2\)最小时,且\((\sum_{i=1}^{n-1}\limits\sum_{j=1}^{i}\limits x_j)^2\)最大

但两个变量明显不好求,所以我们钦定\(\sum_{i=1}^{n-1}\limits\sum_{j=1}^{i}\limits x_j\)不变,去找每一个不同的和对应的最小的\(\sum_{i = 1}^{n-1}\limits (\sum_{j=1}^{i} \limits x_j)^2\)

这里我们的转移方程也出来了:\(f_{i,j}\) 表示考虑前 \(i\) 个差分数组,\(\sum_{i=1}^{n-1}\limits\sum_{j=1}^{i}\limits x_j=j\) 时,最小的\(\sum_{i = 1}^{n-1}\limits (\sum_{j=1}^{i} \limits x_j)^2\)

这里应该提前从小到大排个序

考虑新进来一个 \(x_{i+1}\) 对答案的影响,设 \(sum_i\) 为前 \(i\) 个差分序列的和

  • 1:如果放在序列右面:

\[\huge f_{i+1,j+x_{i+1}+sum_i}=\min f_{i,j}+(x_{i+1}+sum_i)^2 \]

  • 2:如果放在序列左面:相当于之前填的序列整体右移

贡献为$$\sum_{j=1}^{i} (x_j+x_{i+1})^2- \sum_{j=1}^{i} x_j^2$$

\[=\sum_{j=1}^{i} {x_j}^2+\sum_{j=1}^{i} 2*x_j*x_{i+1}+\sum_{j=1}^{i} x_{i+1}^2- \sum_{j=1}^{i} x_j^2 \]

\[=\sum_{j=1}^{i} 2*x_j*x_{i+1}+\sum_{j=1}^{i} x_{i+1}^2 \]

\[=2*j*x_{i+1}+i*x_{i+1}^2 \]

最后加他本身的 \(x_{i+1}^2\)

\[\huge f_{i+1,j+x_{i+1}*(i+1)}=\min f_{i,j}+2*j*x_{i+1}+(i+1)*x_{i+1}^2 \]

点击查看代码
#include<bits/stdc++.h>
const int maxn=1e4+10;
using namespace std;
int n,a[maxn],x[maxn],f[2][500001],sum[maxn],top,s,ans;


int main()
{
//	freopen("set1.in","r",stdin);
//	freopen("T.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		x[i-1]=i>1?a[i]-a[i-1]:0;
//		cout<<x[i-1]<<endl;
	}
	sort(x+1,x+n);
	for(int i=1;i<n;i++) sum[i]=sum[i-1]+x[i];
	memset(f,0x7f,sizeof f);
	f[1][x[1]]=x[1]*x[1];
	top=x[1];
	int temp=0;
	for(int i=1;i<n-1;i++)
	{
		temp^=1;
		top+=x[i+1]*(i+1);
		for(int j=0;j<=top;j++)
		{
			s=j+sum[i+1];
//			cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
//			if(s>top) continue;
			f[temp^1][s]=min(1ll*f[temp^1][s],f[temp][j]+1ll*sum[i+1]*sum[i+1]);
		}
		for(int j=0;j<=top;j++)
		{
			s=j+x[i+1]*(i+1);
//			if(s>top) continue;
			f[temp^1][s]=min(1ll*f[temp^1][s],f[temp][j]+1ll*x[i+1]*x[i+1]*(i+1)+2ll*j*x[i+1]);
		}
		memset(f[temp],0x7f,sizeof f[temp]);
	}
	ans=0x7f7f7f7f;
	for(int i=0;i<=top;i++) 
//		cout<<f[(n-1)&1][i]<<endl;
		ans=min(1ll*ans,1ll*n*f[(n-1)&1][i]-1ll*i*i);
			
	cout<<ans<<'\n';
	
	return 0;
}

posted @ 2024-09-11 16:42  _君の名は  阅读(78)  评论(1)    收藏  举报