Matrix Distances

题目链接

题意:

给一个n*m的矩阵,每个位置有个颜色值,相同颜色值两两求曼哈顿距离,问总和是多少(选取顺序不同也算不同,即两个点会产生两次贡献)。

思路:

假设 n = m = 1 0 3 n=m=10^3 n=m=103,那么时间复杂度最坏要维持在 O ( n 2 l o g n ) O(n^2log n) O(n2logn)。如果对每个点进行与其他相同颜色的点的求和,这个求和就需要是在 O ( l o g n ) O(logn) O(logn)以内的。考虑一种颜色,因为是曼哈顿距离所以x和y可以分开来求,整体求是不太可能的,因为每个点都需要和其他所有点都算一遍,考虑递推。只考虑x,发现递推的话,点的顺序是不太重要的,所以可以排好序后一个一个算,假如前i-2个点分别到第i-1个点的距离之和是lst,i和i-1点的距离是dis,那么到第i个点的距离就是 l s t + d i s ∗ ( i − 1 ) lst+dis*(i-1) lst+dis(i1),总贡献就是把所有点的都累加起来就行了,因为两个点直接会产生两次贡献,所以结果乘2。同理y。

不过还有一个问题,颜色个数很多,每个颜色的点的个数也不固定,开静态会爆空间。开动态会比较难写而且慢。考虑因为颜色不会对结果产生影响,所以不需要管颜色具体是什么,我们只需要相同颜色的在一块,并且x或y排好序就行了。

考虑xy分开存储,对x,存储颜色和x值的二元组。然后直接排序就可以了,颜色在前,排好序后相同颜色的就挤在一起了,相同颜色的也用x值排好序了。y同理。

code:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1005;
typedef long long ll;
 
int n,m;
pair<int,int> x[maxn*maxn],y[maxn*maxn];
int cnt;
 
int main(){
	cin>>n>>m;
	for(int i=1,c;i<=n;i++)
		for(int j=1;j<=m;j++){
			scanf("%d",&c);
			++cnt;
			x[cnt].first=y[cnt].first=c;
			x[cnt].second=i;
			y[cnt].second=j;
		}
	sort(x+1,x+cnt+1);
	sort(y+1,y+cnt+1);
	
//	for(int i=1;i<=cnt;i++)
//		printf("%d %d\n",x[i].first,x[i].second);
	
	ll ans=0;
	for(int i=1,wid,lst;i<=cnt;i++){
		if(x[i].first!=x[i-1].first)wid=lst=0;
		else ans+=lst+=1ll*wid*(x[i].second-x[i-1].second);
		wid++;
	}
	for(int i=1,wid,lst;i<=cnt;i++){
		if(y[i].first!=y[i-1].first)wid=lst=0;
		else ans+=lst+=1ll*wid*(y[i].second-y[i-1].second);
		wid++;
	}
	cout<<(ans<<1)<<endl;
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值