zoukankan      html  css  js  c++  java
  • 洛谷P2345 奶牛集会

    题目背景

    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(n^2)是不能过的,但是如果先按照v排序,再来暴力就能A掉,但是有没有更好的方法呢?因为已经按照v排序了,所以排除v的干扰,关键就是怎么快速求sum{|xi - xj|},绝对值化简出来要么是xi - xj,要么是xj - xi,那么我们找i之前有多少个比i小的num1,它们的和是多少x1,有多少个比i大的num2,它们的和是多少x2,那么很显然,ans += v * (num1 * x - x1 + x2 - num2 * x).那么怎么快速求出num和x1,x2呢?很显然,树状数组。
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    long long n,c[50010],maxn,num[50010],ans;
    
    struct node
    {
        long long v,x;
    }e[20010];
    
    long long lowbit(long long x)
    {
        return x & (-x);
    }
    
    void add(long long x,long long d)
    {
        while (x <= maxn)
        {
            c[x] += d;
            x += lowbit(x);
        }
    }
    
    long long query(long long x)
    {
        long long cnt = 0;
        while (x)
        {
            cnt += c[x];
            x -= lowbit(x);
        }
        return cnt;
    }
    
    void add2(long long x,long long d)
    {
        while (x <= maxn)
        {
            num[x] += d;
            x += lowbit(x);
        }
    }
    
    long long query2(long long x)
    {
        long long cnt = 0;
        while (x)
        {
            cnt += num[x];
            x -= lowbit(x);
        }
        return cnt;
    }
    
    bool cmp(node a,node b)
    {
        return a.v < b.v;
    }
    
    int main()
    {
        scanf("%lld",&n);
        for (int i = 1; i <= n; i++)
        {
        scanf("%lld%lld",&e[i].v,&e[i].x);
        maxn = max(maxn,e[i].x);
        }
        sort(e + 1,e + 1 + n,cmp);
        long long t = 0;
        for (int i = 1; i <= n; i++)
        {
            long long x = e[i].x,v = e[i].v;
            long long x1 = query(x - 1),num1 = query2(x - 1);
            long long num2 = i - 1 - num1,x2 = t - x1;
            t += e[i].x;
            ans += v * (num1 * x - x1 + x2 - num2 * x);
            add(x,x);
            add2(x,1);
        }
        printf("%lld
    ",ans);
    
        return 0;
    }
     
  • 相关阅读:
    拖拽模块move2
    拖拽模块move1
    String类和StringBuilder
    你真的会二分查找吗
    C++中关于new及动态内存分配的思考
    【转】Github 上传代码
    HDU4801·二阶魔方
    POJ2676,HDU4069解决数独的两种实现:DFS、DLX
    读书笔记
    SpringBoot-------实现多数据源Demo
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7500825.html
Copyright © 2011-2022 走看看