题解:P1861 星之器

前言

这为啥能想到来着。

思路分析

首先你发现答案只和初态和末态有关。

于是可以考虑定义势能,答案为势能的减少量。

经过仔细读题后发现,每次我们选择在一行或者一列操作,那么每一行和每一列的势能都是相对独立的。

于是我们只需要考虑在一行进行操作的势能变化,一行的势能是本行所有元素的势能之和,原图的势能就是行势能与列势能之和。

我们设 \(f(x)\) 表示在行内位置为 \(x\) 的元素所具有的势能,如果我们操作 \(x_1,x_2,x_1<x_2\),那么我们有:

\[f(x_1)+f(x_2)-f(x_1+1)-f(x_2-1)=x_2-x_1-1 \]

我们需要构造势能函数 \(f(x)\) 满足上面的式子。

我们尝试对上面的式子进行一点变换。

\[f(x_1+1)-f(x_1)-(x_1+1)=f(x_2)-f(x_2-1)-x_2 \]

我们让左右两边都为 \(0\) 即可,也就是,

\[f(x_1+1)-f(x_1)=x_1+1 \]

不妨设 \(f(0)=0\),那么对于 \(f(x)\),我们有,

\[f(x)=\frac{x(x+1)}{2} \]

然后就可以算初态和末态的势能了。

复杂度 \(O(nm)\)

代码实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,a,cnt1[205],cnt2[205],ans1,ans2;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a;
			cnt1[i]+=a,cnt2[j]+=a;
		}
	}
	for(int i=1;i<=n;i++){
		ans1+=i*(i+1)/2*cnt1[i];
		cnt1[i]=0;
	}
	for(int i=1;i<=m;i++){
		ans1+=i*(i+1)/2*cnt2[i];
		cnt2[i]=0;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a;
			cnt1[i]+=a,cnt2[j]+=a;
		}
	}
	for(int i=1;i<=n;i++){
		ans2+=i*(i+1)/2*cnt1[i];
		cnt1[i]=0;
	}
	for(int i=1;i<=m;i++){
		ans2+=i*(i+1)/2*cnt2[i];
		cnt2[i]=0;
	}
	cout<<ans1-ans2;
	return 0;
}
posted @ 2025-03-29 14:22  _Kenma  阅读(35)  评论(0)    收藏  举报