POJ 1990 MooFest
题意:有m头牛,每头牛有两个值,v和x,两两之间有一个值,设v分别为v1,v2,x为x1,x2,则它们之间的值为abs(x1-x2) * Max(v1,v2),求所有m*(m-1)/2对牛之间值的总和。
思路:咋看第一眼都是暴力这个优秀算法,不过暴力肯定是不行的,所以要树状数组优化
我们可以先将牛以V排序,这时只需要考虑每一个 i 左右的X的情况
// #include<bits/stdc++.h> #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> // for memset #include <vector> // push_back() // vector<int>().swap(v); #include <set> //multiset set<int,greater<int>> //big->small #include <map> #include <stack> // top() #include <queue> // front() // priority_queue<T,vector<T>,greater<T> > #include <cmath> // auto &Name : STLName Name. #include <utility> #include <sstream> #include <string> // __builtin_popcount (ans); // 获取某个数二进制位1的个数 #include <cstdlib> // rand() #define IOS ios_base::sync_with_stdio(0); cin.tie(0) using namespace std; typedef long long ll; int lowbit(int x){ return x&(-x);} const int maxn = 20010; struct Node { int x,v; bool operator< (const Node& s)const{return v<s.v;} }node[maxn]; int n; int treeCount[maxn]; int treeDis[maxn]; ll sum(int x,int *t) { ll ans=0; while(x) { ans+=t[x]; x-=lowbit(x); } return ans; } void add(int x,int v,int *t) { while(x<maxn) { t[x]+=v; x+=lowbit(x); } } ll solve() { ll ans=0; ll totalDis=0; memset(treeCount , 0 , sizeof(treeCount)); memset(treeDis , 0 , sizeof(treeDis)); sort(node,node+n); for(int i=0;i<n;i++) { ll count=sum(node[i].x,treeCount); ll dis=sum(node[i].x,treeDis); ans+=node[i].v*(count*node[i].x-dis); ans+=node[i].v*((totalDis-dis-(i-count)*node[i].x)); totalDis += node[i].x; add(node[i].x , 1 , treeCount); add(node[i].x , node[i].x , treeDis); } return ans; } int main(void) { while(scanf("%d",&n)!=EOF) { for(int i=0;i<n;i++) scanf("%d%d",&node[i].v,&node[i].x); printf("%lld\n",solve()); } return 0; }