题意:牛的听力为v,两头牛i,j之间交流,需要max(v[i], v[j])*dist(i,j)的音量。应该说,题意是说,v[i]越小,听力越好。
求所有牛交谈时叫声总和∑(max(v[i],v[j])*abs(dist[j]-dist[i]) ) )
思路:先对牛按照v从小到大排序。对于牛i,它与比他听力还小的牛之间交谈需要音量都是v[i],再乘以之间的距离就可以了。在排好序后,假设:
count[i]:比i听力小的且x坐标比第i头牛小的牛总数
total[i]:count[i]中那些牛的x坐标总和
alltotal:表示所有比第i头牛听力小的牛的总数的话
那么,原题要求的式子就成了
∑( v[i] * 所有比i听力小的牛到i的总距离 )
=∑( v[i] * (count[i]*x[i] – total + alltotal – total – (i – count[i] – 1) * x[i] ) )
其中,count[i]*x[i] – total表示所有比i听力小且在它左边的牛们到i的距离总和, alltotal – total – (i – count[i] – 1) * x[i] ) 表示所有比i听力小且在它右边的牛们到i的距离总和。这个有点难理解,自己画个图试试看。
剩下的关键就在,如何求count[i]和total[i]更快。因为如果排好序后是扫一遍所有牛的坐标的话,时间复杂度就是n^2了,不行。所以想到了树状数组。树状数组用于动态的求一个数组前i个数的总和。
求所有牛交谈时叫声总和∑(max(v[i],v[j])*abs(dist[j]-dist[i]) ) )
思路:先对牛按照v从小到大排序。对于牛i,它与比他听力还小的牛之间交谈需要音量都是v[i],再乘以之间的距离就可以了。在排好序后,假设:
count[i]:比i听力小的且x坐标比第i头牛小的牛总数
total[i]:count[i]中那些牛的x坐标总和
alltotal:表示所有比第i头牛听力小的牛的总数的话
那么,原题要求的式子就成了
∑( v[i] * 所有比i听力小的牛到i的总距离 )
=∑( v[i] * (count[i]*x[i] – total + alltotal – total – (i – count[i] – 1) * x[i] ) )
其中,count[i]*x[i] – total表示所有比i听力小且在它左边的牛们到i的距离总和, alltotal – total – (i – count[i] – 1) * x[i] ) 表示所有比i听力小且在它右边的牛们到i的距离总和。这个有点难理解,自己画个图试试看。
剩下的关键就在,如何求count[i]和total[i]更快。因为如果排好序后是扫一遍所有牛的坐标的话,时间复杂度就是n^2了,不行。所以想到了树状数组。树状数组用于动态的求一个数组前i个数的总和。
所以,把count作为一个树状数组,如果在坐标x上有一头牛,那么count[x] = 1。这样求i之前有多少头牛,就是count(i)的一个查询。把total同样作为一个树状数组,如果坐标x上有一头牛,那么total[x] += x。这是因为total数组表示的是距离。这样求i之前听力小于v[i]且在i左边的牛总数,就是total(i)的查询。
count[i]之所以是小于,是因为x坐标唯一
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 20005;
long long Count[maxn], Total[maxn];
struct Cow
{
int vol, x;
}cow[maxn];
bool cmp(Cow p, Cow q)
{
if(p.vol == q.vol)
return p.x < q.x;
return p.vol < q.vol;
}
int lowbit(int lo)
{
return lo & (-lo);
}
void modify1(int pos, int value)
{
while(pos < maxn)
{
Count[pos] += value;
pos += lowbit(pos);
}
}
void modify2(int pos, int value)
{
while(pos < maxn)
{
Total[pos] += value;
pos += lowbit(pos);
}
}
long long getsum1(int pos)
{
long long sum = 0;
while(pos > 0)
{
sum += Count[pos];
pos -= lowbit(pos);
}
return sum;
}
long long getsum2(int pos)
{
long long sum = 0;
while(pos > 0)
{
sum += Total[pos];
pos -= lowbit(pos);
}
return sum;
}
int main()
{
int n;
long long allTotal, ans;
while(cin >> n)
{
allTotal = ans = 0;
memset(Count, 0, sizeof(Count));
memset(Total, 0, sizeof(Total));
for(int i = 1; i <= n; i++)
scanf("%d%d", &cow[i].vol, &cow[i].x);
sort(cow + 1, cow + n + 1, cmp);
for(int i = 1; i <= n; i++)
{
int x = cow[i].x;
ans += cow[i].vol * (getsum1(x)*x - getsum2(x) + allTotal - getsum2(x) - (i-getsum1(x) - 1)*x );
//因为x坐标不能重复,所以getsum1(x)取的的肯定是听力小的,而且x坐标比他小的
modify1(x, 1);
modify2(x, x);
allTotal += x;
}
cout << ans << endl;
}
return 0;
}
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define F(i,START,END) for (int i=START;i<=END;i++)
const int maxn = 20005;
struct Cow
{
int vo, x;
bool operator < (const Cow &other) const
{
if(vo == other.vo)
return x < other.x;
return vo < other.vo;
}
}cow[maxn];
struct treearray
{
long long C[maxn], n;
treearray(){}
treearray(int _n){Clear(), n = _n;}
void Clear()
{
memset(C, 0, sizeof(C));
}
int lowbit(int lo)
{
return lo & (-lo);
}
void modify(int pos, int value)
{
while(pos < n)
{
C[pos] += value;
pos += lowbit(pos);
}
}
long long getsum(int pos)
{
long long sum = 0;
while(pos > 0)
{
sum += C[pos];
pos -= lowbit(pos);
}
return sum;
}
}Count, Total;
int main()
{
int n;
while(cin >> n)
{
long long ans = 0, allTotal = 0;
F(i, 1, n)
scanf("%d%d", &cow[i].vo, &cow[i].x);
sort(cow + 1, cow + n + 1);
Total = treearray(20002);
Count = treearray(20002);
F(i, 1, n)
{
int x = cow[i].x;
ans += cow[i].vo * (Count.getsum(x)*x - Total.getsum(x) + allTotal - Total.getsum(x) - (i - Count.getsum(x) - 1) * x);
Count.modify(x, 1);
Total.modify(x, x);
allTotal += x;
}
cout << ans << endl;
}
return 0;
}