ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】P5094 - Moofest

2021-07-24 23:33:32  阅读:202  来源: 互联网

标签:小于 int 题解 sum times Moofest 坐标值 奶牛 P5094


题目大意

题目链接

给定\(n\)头奶牛,已知每头奶牛有其对应的听力和位置坐标。设\(v_{i}\)为第\(i\)头奶牛的听力,\(x_{i}\)为第\(i\)头奶牛的坐标。设\(dis(i, j)\)为第\(i\)头奶牛和第\(j\)头奶牛的坐标之差,则一对奶牛谈话需要的音量为\(max(v_{i}, v_{j}) \times dis(i, j)\)。试求所有的\(n \times (n - 1) \div 2\)头奶牛谈话需要的最小音量总和。

解题思路

显然,通过对算法标签的分析,我们可以知道这道题是一道数据结构题。

题目给出的式子过于繁琐,考虑尽量简化这个式子。显然,\(max(v_{i}, v_{j})\)这一项是比较容易简化的。假设我们将所有的奶牛按听力从小到大排序,那么对于一对奶牛\((i, j)\),在\(i < j\)的情况下,它们交谈所需要的听力显然是\(v_{j}\)。因此,我们可以通过按听力从小到大排序来简化\(max(v_{i}, v_{j})\)这一项。

如果按听力从小到大排序,那么我们在考虑第\(i\)头奶牛对音量总和的贡献时,仅考虑第\(1\)头奶牛至第\(i - 1\)头奶牛与第\(i\)头奶牛谈话的音量,最后也能求出所有\(n \times (n - 1) \div 2\)对奶牛的音量总和。

接下来,我们考虑\(dis(i, j)\)这一项的求解。显然,假设\(i < j\),则对于所有这样一对奶牛\((i, j)\),\(v_{i}\)一定小于\(v_{j}\),但是\(x_{i}\)可能大于等于\(x_{j}\)。因此,我们需要分类讨论,将第\(i\)头奶牛前的奶牛分成两类:

  1. \(j < i, x_{j} < x_{i}\)

  2. \(j < i, x_{j} \geq x_{i}\)

我们可以维护两个信息:第\(i\)头奶牛前,坐标值小于\(x_{i}\)的奶牛的数量;第\(i\)头奶牛前,坐标值小于\(x_{i}\)的奶牛的坐标值之和。设\(t1_{i}\)为坐标值小于\(x_{i}\)的奶牛的数量,\(t2_{i}\)为坐标值小于\(x_{i}\)的奶牛的坐标值之和。

我们可以推算出第\(i\)头奶牛前,坐标值大于等于\(x_{i}\)的奶牛的总数:奶牛总数\(i\) $ - $ 坐标值小于\(x_{i}\)的奶牛总数 $ - $ \(1\)。设\(sum\)为\(\sum\limits_{j = 1}^{i - 1} x_{j}\),则第\(i\)头奶牛前所有坐标值大于等于\(x_{i}\)的奶牛的坐标值之和为\(sum\) $ - $ 坐标值小于\(x_{i}\)的奶牛的坐标值之和。

每次修改时,我们在数据结构\(1\)中\(x_{i}\)的位置加上\(1\),表示这个坐标的奶牛又出现了一次;在数据结构\(2\)中\(x_{i}\)的位置加上\(x_{i}\)。这样,我们每次查询时,只需要查找\(x_{i}\)位置前,数据结构\(1\)的前缀和即可求出坐标值小于等于\(x_{i}\)的奶牛总数,查找数据结构\(2\)的前缀和即为所有坐标值小于等于\(x_{i}\)的奶牛的坐标值之和。

抓住关键词前缀和,我们可以在知识库里检索出有相应特征的数据结构:树状数组。我们用两个树状数组分别维护上文提到的两个信息,即可方便快捷地求出每一头奶牛对音量总和的贡献。

我们设\(cnt\)为第\(i\)头奶牛前坐标值小于\(x_{i}\)的奶牛数量,\(sum\)为第\(i\)头奶牛前坐标值小于\(x_{i}\)的奶牛的坐标值之和,\(pos\)为\(\sum\limits_{j = 1}^{i - 1} x_{j}\)。则第\(i\)头奶牛与第\(i\)头奶牛前坐标值小于\(x_{i}\)的奶牛的距离总和为\(cnt \times x_{i} - sum\),第\(i\)头奶牛与第\(i\)头奶牛前坐标值大于等于\(x_{i}\)的奶牛的距离总和为\((pos - sum) - (i - cnt - 1) \times x_{i}\)。第\(i\)头奶牛的贡献即为\((cnt \times x_{i} - sum) \times v_{i} + \left[(pos - sum) - (i - cnt - 1) \times x_{i}\right] \times v_{i}\)。累加所有奶牛的贡献,就是最终谈话的音量总和。

最后提出一个容易错误的点,如果有同学的样例输出\(53\),说明树状数组的上界没有弄清楚。树状数组更新的位置为\(x_{i}\),即奶牛的坐标。因此,树状数组的上界应该是\(max(x_{i})\)而非\(n\)。

参考代码

在此附上本人的\(AC\)代码,仅供参考,请勿抄袭:

#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 50005
#define int long long

struct node
{
	int voise, pos;
}cow[maxn];

int n, m;
int cnt[maxn], sum[maxn];

bool cmp(node a, node b)
{
	return a.voise < b.voise;
}

int lowbit(int x)
{
	return x & (-x);
}

void add_cnt(int p, int x)
{
	for (int i = p; i <= m; i += lowbit(i))
		cnt[i] += x;
}

int query_cnt(int p)
{
	int Sum = 0;
	for (int i = p; i; i -= lowbit(i))
		Sum += cnt[i];
	return Sum;
}

void add_sum(int p, int x)
{
	for (int i = p; i <= m; i += lowbit(i))
		sum[i] += x;
}

int query_sum(int p)
{
	int Sum = 0;
	for (int i = p; i; i -= lowbit(i))
		Sum += sum[i];
	return Sum;
}

signed main()
{
	int pos_sum = 0, ans = 0;
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld%lld", &cow[i].voise, &cow[i].pos);
		m = max(m, cow[i].pos);
	}
	sort(cow + 1, cow + n + 1, cmp);
	for (int i = 1; i <= n; i++)
	{
		int cnt = query_cnt(cow[i].pos);
		int sum = query_sum(cow[i].pos);
		ans += (cnt * cow[i].pos - sum) * cow[i].voise;
		ans += ((pos_sum - sum) - (i - cnt - 1) * cow[i].pos) * cow[i].voise;
		add_cnt(cow[i].pos, 1);
		add_sum(cow[i].pos, cow[i].pos);
		pos_sum += cow[i].pos;
	}
	printf("%lld\n", ans);
	return 0;
}

这是蒟蒻的第一篇题解,如果有描述不清楚的地方请多多见谅,本人也会继续努力,写出质量更高的题解。

标签:小于,int,题解,sum,times,Moofest,坐标值,奶牛,P5094
来源: https://www.cnblogs.com/Ling-Lover/p/p5094.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有