我是靠谱客的博主 炙热世界,最近开发中收集的这篇文章主要介绍P2345 奶牛集会(树状数组or模拟),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目背景

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模拟)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部