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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值