概述
题目背景
MooFest, 2004 Open
题目描述
约翰的N 头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很
多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出max{Vi; Vj}×|Xi − Xj | 的音量,其中Vi 和Vj 分别是第i 头和第j 头奶牛的听力。假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。
输入输出格式
输入格式:
• 第一行:单个整数N,1 ≤ N ≤ 20000
• 第二行到第N + 1 行:第i + 1 行有两个整数Vi 和Xi,1 ≤ Vi ≤ 20000; 1 ≤ Xi ≤ 20000
输出格式:
• 单个整数:表示所有奶牛产生的音量之和
输入输出样例
输入样例#1: 复制
4
3 1
2 5
2 6
4 3
输出样例#1: 复制
57
说明
朴素O(N2)
类似于归并排序的二分O(N logN)
树状数组O(N logN)
思路:这个题要说思路还是不是很难的,不过容易出错,为了防止出错以及后续看不懂,我们先来一个简单的模拟解法,代码如下
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 20010;
long long n, tempSum, ans;
struct Node {
int x, v;
}node[maxn];
int cmp(Node a, Node b) {
return a.v > b.v;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> node[i].v >> node[i].x;
}
sort(node + 1, node + n + 1, cmp);
for (int i = 1; i <= n; i++) {
long long sum = 0;
for (int j = i + 1; j <= n; j++) {
if (node[j].x <= node[i].x) {
sum += node[i]. x - node[j].x;
} else {
sum += (node[j].x - node[i].x);
}
}
ans += node[i].v * sum;
}
cout << ans << endl;
}
是不是非常简单,要是你只满足于做出这道题,那么下面你就可以不用看了,若你还想进一步优化这个题目,那么你可以继续看看下面的树状数组的讲解
首先,根据上面我们模拟的做法,我们知道其实求的就是该点的V值乘以V值比他小的点到该点的横坐标的和,将这个过程执行n次并且把每次结果相加就可以得到最后的结果,在模拟的过程中,我们是把V值从大到小排列,那么在树状数组中,我们使用从小到大排列
我们用c【】来表示该树状数组里面的值,也就是这个区间内X值的和,num【】数组表示这区间内的点,sum表示X的坐标小于等于传入参数的和,cnt表示X的坐标小于等于传入参数的个数,因为我们是按V值从小到大排序,那么我们取出的每一个Node可以和它之前的Node进行运算,然后运算结果有俩种情况需要讨论:
1.之前的结点的X值比当前的节点的X值小,那么 ans = 当前节点的V值(node【i】.v)乘以所有之前所有结点到当前结点的X值的和,所以ans = node【i].v * (node[i].x * cnt- sum);解释一下就是当前节点的值已经在运算过程中抵消了,我们是这样运算的,共有cnt个结点的X值小于当前的X值,那么我们求他们到当前X值的距离可以先算原点到当前X值的总距离然后减去每个点到原点的总距离即可
2.之前的节点的X值比当前的节点的X值大,那么我们每次用tot减去比节点X小的节点的坐标的和,得到的就是所有比当前节点X的值大的和,然后减去比当前节点X大的节点的个数乘以当前的节点的X值,也就计算出比X值大的节点到X的总距离,稍微脑袋里模拟一下便知道了,tot表示之前出现的点的X坐标的和
#include<iostream>
#include<algorithm>
using namespace std;
#define lowbit(i) ((i) & (-i))
const int maxn = 20010;
struct Node{
int v, x;
}node[maxn];
int cmp(Node a, Node b) {
return a.v < b.v;
}
long long n, sum, cnt, ans, tot;
int c[maxn], num[maxn];
void update(int x, int v) {
for (int i = x; i < maxn; i += lowbit(i)) {
c[i] += v;
num[i] += 1;
}
}
void getSum(int x) {
for (int i = x; i > 0; i -= lowbit(i)) {
sum += c[i];
cnt += num[i];
}
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> node[i].v >> node[i].x;
}
sort(node + 1, node + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
sum = 0, cnt = 0;
update(node[i].x, node[i].x);
getSum(node[i].x);
tot += node[i].x;
ans += node[i].v * (cnt * node[i].x - sum + tot - sum - node[i].x * (i - cnt));
}
cout << ans << endl;
return 0;
}
最后
以上就是炙热世界为你收集整理的P2345 奶牛集会(树状数组or模拟)的全部内容,希望文章能够帮你解决P2345 奶牛集会(树状数组or模拟)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复