题目大意:Farmer John又来恶心我们了!这次他带来了一些牛,这些牛排成一列,他们的位置给出,每一个牛有一个音调。这些牛每两只牛之间都要互相交流,但是交流的时候会有一些花费,i,j两只牛的cost = max(vi,vj) * |posi - posj|。求所有牛之间互相交流的cost和。
思路:一开始我还以为是最大或者最小花费,后来仔细读题发现想多了,就是单纯的统计,但是数据范围2w显然不能n^2的统计,我们需要来想一些优化的方法。
对于所有的牛对来说,最后计算cost的时候是决定于音调高的那一头牛身上。所以就考虑能不能把音调从低到高排序,然后不断的往其中加牛。这样每次的牛加进去的时候,之前的所有牛的声调都比加进去的低,也就可以用新加进去的牛来计算了。
注意到每一个新加进来的牛需要向ans中累加Σvx * |posx - posi|这么多,vx已经知道了,那么怎么求距离之和呢?我的方法是维护4个树状数组,分别统计在x前面的所有点到原点的距离之和,x前面有多少牛;x后面的点的到原点的距离之和,x后面有多少牛。这样就可以通过cnt * posx - Σpos_pred来计算出x前面的距离x之和,后面的也同理。
分析下时间复杂度,O(nlogn),水过吧。。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 200010 using namespace std; struct Complex{ int val,pos; bool operator <(const Complex &a)const { return val < a.val; } void Read() { scanf("%d%d",&val,&pos); } }point[MAX]; int points; long long pred[MAX],cnt1[MAX]; long long succ[MAX],cnt2[MAX]; inline void FixPred(int x); inline void FixSucc(int x); inline long long GetPred(int x); inline long long GetSucc(int x); int main() { cin >> points; for(int i = 1;i <= points; ++i) point[i].Read(); sort(point + 1,point + points + 1); long long ans = 0; for(int i = 1;i <= points; ++i) { ans += GetPred(point[i].pos) * point[i].val; ans += GetSucc(point[i].pos) * point[i].val; FixPred(point[i].pos); FixSucc(point[i].pos); } cout << ans << endl; return 0; } inline void FixPred(int x) { for(int i = x;i < MAX;i += i&-i) { pred[i] += x; ++cnt1[i]; } } inline void FixSucc(int x) { for(int i = x;i;i -= i&-i) { succ[i] += x; ++cnt2[i]; } } inline long long GetPred(int x) { long long re = 0,cnt = 0; for(int i = x;i;i -= i&-i) re += pred[i],cnt += cnt1[i]; return cnt * x - re; } inline long long GetSucc(int x) { long long re = 0,cnt = 0; for(int i = x;i < MAX;i += i&-i) re += succ[i],cnt += cnt2[i]; return re - cnt * x; }
原文地址:http://blog.csdn.net/jiangyuze831/article/details/40144561