CF433C 题解

CF433C

思路

出于习惯,调换 \(n\)\(m\)\(n\) 为数组长度,\(m\) 为值域。

考虑枚举被替换的 \(a_i\)。枚举值域 \(1\)\(m\) 的权值 \(x\)

每个权值为 \(x\) 的点 \(a_i\) 的贡献是 \(\mid a_i-a_{i-1} \mid+\mid a_i-a_{i+1} \mid\)。由于 \(a_i\) 被更改,贡献会随之变化,与之有关的是所有 \(a_i\) 的左右两边的点。将这些点全部放进 vector 里。设 \(p_x\) 表示所有这样的点。

如果要把 \(x\) 改为 \(y\) 并令 \(ans\) 最小,受影响的是 \(\sum \mid x-p_{i,j} \mid\) 变为 \(\sum \mid y-p_{i,j} \mid\),要使 \(\sum \mid y-p_{i,j} \mid\) 最小。

\(\textbf{初一}\) 知识,当取 \(y\)\(p_{i,0}\)\(p_{i,len}\) 的中位数时,式子最小。一开始我以为是平均数,整半天。

用最开始算出的不修改答案 \(num\) 减去 \(\sum \mid x-p_{i,j} \mid\) 加上 \(\sum \mid y-p_{i,j} \mid\) 得到修改 \(x\) 的最小答案,再取最小值。

code

int n,m,a[maxn],ans,num;
vector<int> p[maxn];
int sum,x,sum1;

int T;
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);

	m=read();n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		if(i!=1)num+=abs(a[i]-a[i-1]);
	}
	for(int i=1;i<=n;i++){
		if(a[i-1]&&a[i-1]!=a[i])p[a[i]].push_back(a[i-1]);
		if(a[i+1]&&a[i+1]!=a[i])p[a[i]].push_back(a[i+1]);
	}
	ans=num;
	for(int i=1;i<=m;i++){
		if(p[i].size()){
			sort(p[i].begin(),p[i].end());
			sum=sum1=0;x=p[i][p[i].size()/2];
			for(int j=0;j<p[i].size();j++){
				sum+=abs(i-p[i][j]);
				sum1+=abs(x-p[i][j]);
			}
			ans=min(ans,num-sum+sum1);
		}
	}
	printf("%lld\n",ans);
}

posted @ 2024-05-08 18:15  yhddd  阅读(15)  评论(0编辑  收藏  举报