zoukankan      html  css  js  c++  java
  • USACO 2004 MooFest 奶牛集会

    题目

    问题描述

    约翰的n 头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出max{Vi;Vj}×|Xi−Xj| 的音量,其中Vi和Vj分别是第i 头和第j 头奶牛的听力。

    假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

    输入文件

    第1行:一个整数n(1n20,000)

    第2..n+1行:第i+1行有两个整数Vi(1Vi20,000)和Xi(1Xi20,000)

    输出文件

    仅一行:一个整数表示所有奶牛产生的音量之和。

    样例输入输出

    moofest.in

    4
    3 1
    2 5
    2 6
    4 3

    moofest.out

    57

    分析

    朴素暴力枚举:枚举i,j,O(n2)。N最大到20000,放弃吧。

    首先来观察一下这个音量的计算公式:首先在两只牛的听力v当中取较大值,然后和两者的坐标差相乘。

    既然取较大的v,我们不妨把所有奶牛按照v从大到小排序。这样每次取出的奶牛和它右边的奶牛计算即可。

    然后再来看如何处理坐标差。因为当前选出的这头奶牛一定是和它右边,也就是较小的奶牛进行计算,所以公式的第一部分是一个定值。那么我们不难想到在这里可以合并同类项。对于一个奶牛它所对应的左半边音量之和的公式就是:当前奶牛听力*(左边奶牛的个数*当前奶牛的坐标-左边所有奶牛的坐标和)。右边也就不难同理得出了。

    要计算坐标和,那就树状数组呗。

    程序

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int MAXN = 20000 + 1;
     4 struct node
     5 {
     6     int x,v,id;
     7 }cow[MAXN];
     8 struct Tree
     9 {
    10     long long sum,num;
    11 }c[MAXN];
    12 int n;
    13 bool cmpv(node a,node b)
    14 {
    15     return a.v>b.v;
    16 }
    17 bool comp(node a,node b)
    18 {
    19     return a.x<b.x;
    20 }
    21 long long ans=0;
    22 int main()
    23 {
    24     freopen("moofest.in","r",stdin);
    25     freopen("moofest.out","w",stdout); 
    26     scanf("%d",&n);
    27     for(int i = 1; i <= n; i++)
    28         scanf("%d%d",&cow[i].v,&cow[i].x);
    29     sort(cow+1,cow+n+1,comp);
    30     for(int i = 1; i <= n; i++)
    31     {
    32         cow[i].id = i;
    33         for(int j = i; j <= n; j += j&-j)
    34         {
    35             c[j].sum+=cow[i].x;
    36             c[j].num++;
    37         }
    38     }
    39     sort(cow+1,cow+n+1,cmpv);
    40     long long ans=0;
    41     for (int i = 1; i <= n; i++)
    42     {
    43         long long sum = 0, num = 0;
    44         for(int j = cow[i].id; j > 0; j -= j&-j)
    45         {
    46             sum += c[j].sum;
    47             num += c[j].num;
    48         }
    49         ans += (num*cow[i].x-sum)*cow[i].v;
    50         sum =- sum, num=-num;
    51         for (int j = n; j > 0; j -= j&-j)
    52         {
    53             sum += c[j].sum;
    54             num += c[j].num;
    55         }
    56         ans += (sum-num*cow[i].x)*cow[i].v;
    57         for(int j = cow[i].id; j <= n; j += j&-j)
    58         {
    59             c[j].sum -= cow[i].x;
    60             c[j].num--;
    61         }
    62     }
    63     printf("%lld",ans);
    64     return 0;
    65 }
  • 相关阅读:
    10. 分离链接散列表
    9. avltree
    8.二叉查找树
    socket listen参数中的backlog 的意义!
    TCP 三次握手和四次挥手中的ACK 为什么总是SYN + 1 或者 FIN +1 而不是+ 其他数值?
    eclipse 快捷键
    内部类
    rabbitmq AmqpClient 使用Topic 交换机同一个channel 同时多个队列 ,多个交换机,C++代码示例
    rabbitMQ 问题
    rabbitmq AmqpClient 使用Topic 交换机投递与接收消息,C++代码示例
  • 原文地址:https://www.cnblogs.com/OIerPrime/p/8976473.html
Copyright © 2011-2022 走看看