P16904 [CCO 2026] Asymmetry

洛谷

提供简单的 \(O(n^2)\) 做法,无需数据结构和三分什么的,只要推式子即可。

考虑 Alice 走完以后 Bob 的行动,如果 Bob 选择自己再修改一列,那么 Alice 可以马上修改 Bob 的对应列,让 Bob 的修改无效,甚至让结果变小。

而如果 Bob 修改 Alice 对应列,那么结果必定会增大,收益较大并且 Alice 之后又必须开一列,那么 Bob 的最优策略必定是一直选择 Alice 的对应列。

我们从 Bob 的角度考虑如何选择,第一种情况是选择和 Alice 的修改对立的位置,第二种是修改其它的位置,改为 \(k\) 或者 \(0\) 即可,我们只要得到最大的收益即可。

而 Alice 不仅要考虑这次修改的收益,还要考虑 Bob 下次操作的收益。我们先枚举每一行,进行计算。

设修改位置的值为 \(l\),对面的位置为 \(r\),修改为 \(x\),其它行修改后 Bob 最多增加的值为 \(o\)

那么会增加 \(|x-r|-|l-r|+\max(o,k-x-|x-r|,x-|x-r|)\)

这时候直接分析太麻烦了,由于每一段全部都是关于 \(x\) 的分段一次函数,那么最后的图像一定还是分段一次函数。

一次函数有单调性,所以我们只需要找到一次函数可能的段的左右端点找到,显然点不会很多,带入求最值即可统计出这次修改的变化量。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,a[2005][2005];
void solve(int &res,int j,int l,int r,int x,int o){
	res=min(res,abs(x-a[j][r])-abs(a[j][l]-a[j][r])+max({o,k-x-abs(a[j][r]-x),x-abs(a[j][r]-x)}));
}
signed main(){
//	freopen("1.in","r",stdin);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)cin>>a[i][j];
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m/2;j++)ans+=abs(a[i][j]-a[i][m-j+1]);
	}
	for(int i=1;i<=m/2;i++){
		int l=i,r=m-i+1;
		int res=1e18;
		int ma=-1,ma2=-1,w1=0,w2=0;
		for(int j=1;j<=n;j++){
			int x=max(k-a[j][l],a[j][l])-abs(a[j][r]-a[j][l]);
			if(x>ma)ma2=ma,w2=w1,ma=x,w1=j;
			else if(x>ma2)ma2=x,w2=j;
		}
		for(int j=1;j<=n;j++){
			int o=(w1==j?ma2:ma);
			solve(res,j,l,r,a[j][r],o);
			solve(res,j,l,r,k/2,o);
			solve(res,j,l,r,(k-o+a[j][r])/2,o);
			solve(res,j,l,r,(k-o+a[j][r])/2+1,o);
			solve(res,j,l,r,(o+a[j][r])/2,o);
			solve(res,j,l,r,(o+a[j][r])/2+1,o);
		}
		swap(l,r);
		ma=-1,ma2=-1,w1=0,w2=0;
		for(int j=1;j<=n;j++){
			int x=max(k-a[j][l],a[j][l])-abs(a[j][r]-a[j][l]);
			if(x>ma)ma2=ma,w2=w1,ma=x,w1=j;
			else if(x>ma2)ma2=x,w2=j;
		}
		for(int j=1;j<=n;j++){
			int o=(w1==j?ma2:ma);
			solve(res,j,l,r,a[j][r],o);
			solve(res,j,l,r,k/2,o);
			solve(res,j,l,r,(k-o+a[j][r])/2,o);
			solve(res,j,l,r,(k-o+a[j][r])/2+1,o);
			solve(res,j,l,r,(o+a[j][r])/2,o);
			solve(res,j,l,r,(o+a[j][r])/2+1,o);
		}
		ans+=res;
	}
	cout<<ans;
	return 0;
}

posted @ 2026-07-17 14:30  huhangqi  阅读(11)  评论(0)    收藏  举报