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 }
原文地址:https://www.cnblogs.com/OIerPrime/p/8976473.html