Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 6265 | Accepted: 2765 |
Description
Each cow i has an associated "hearing" threshold v(i) (in the range 1..20,000). If a cow moos to cow i, she must use a volume of at least v(i) times the distance between the two cows in order to be heard by cow i. If two cows i and j wish to converse, they must speak at a volume level equal to the distance between them times max(v(i),v(j)).
Suppose each of the N cows is standing in a straight line (each cow at some unique x coordinate in the range 1..20,000), and every pair of cows is carrying on a conversation using the smallest possible volume.
Compute the sum of all the volumes produced by all N(N-1)/2 pairs of mooing cows.
Input
* Lines 2..N+1: Two integers: the volume threshold and x coordinate for a cow. Line 2 represents the first cow; line 3 represents the second cow; and so on. No two cows will stand at the same location.
Output
Sample Input
4 3 1 2 5 2 6 4 3
Sample Output
57
Source
题目大意:一群牛参加完牛的节日后都有了不同程度的耳聋,第i头牛听见别人的讲话,别人的音量必须大于v[i],当两头牛i,j交流的时候,交流的最小声音为max{v[i],v[j]}*他们之间的距离。现在有n头牛,求他们之间两两交流最少要的音量和。
解题思路:首先要根据音量f进行排序,这样就可以进行优化,即对于某一头牛i来说,排在他前面的音量都比他小,肯定是用i自身的音量*两者之间的距离。此时的计算公式为:(求解比当前x小的所有和)
(x-x1)*f;
(x-x2)*f;
(x-x3)*f........
综上为:(n*x(x1+x2+x3+.....))*f; 注释:x表示某一头牛当前的位置,x1,x2,x3......等表示排在他前面的牛的位置,f当前这头牛的音量,因为他是最大的音量。(这里的距离我们需要采用树状数组进行求解)
这里有个地方需要解释一下,就是排在这个牛i前面的音量一定都比他小,但是坐标值x不一定比他小,所以我们只能分开处理。
我们可以在建立一个数轴,一个点一个点的放进去,先放进去的音量肯定是小的,把他按照该有的固定位置放进去,这样排在他前面的所有x都比他小就可以按照上面的方法采用树状数组的方法进行区间求和。(这里要放入一个求解一次他左边和右边的值,左边就是比当前x小的,右边是比当前x大的)。
下面介绍比当前值x大的情况计算方法:
(x1-x)*f;
(x2-x)*f;
(x3-x)*f........
综上:((x1+x2+x3+......)-n*x)*f;
这里的n值就应该等于放进去的所有牛的个数-前面已经计算过的比他x小的个数:i-nn;
(x1+x2+x3+...)就应该等于总和减去比他小的x的和。
要用long long !!!
这样讲起来很复杂,详情请看代码实现~~~~不懂得评论
详见代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
struct node
{
ll f,x;
} s[20010];
int n;
ll c1[20010],c2[20010];
ll a1[20010],a2[20010];
bool cmp(node a,node b)
{
return a.f<b.f;
}
ll lowbit(ll k)
{
return k&(-k);
}
void add1(ll k,ll num)
{
while (k<20010)
{
c1[k]+=num;
k+=lowbit(k);
}
}
void add2(ll k,ll num)
{
while (k<20010)
{
c2[k]+=num;
k+=lowbit(k);
}
}
ll sum1(ll k)
{
ll sm=0;
while (k)
{
sm+=c1[k];
k-=lowbit(k);
}
return sm;
}
ll sum2(ll k)
{
ll sm=0;
while (k)
{
sm+=c2[k];
k-=lowbit(k);
}
return sm;
}
int main()
{
while (~scanf("%d",&n))
{
for (int i=1; i<=n; i++)
{
scanf("%lld%lld",&s[i].f,&s[i].x);
}
memset(a1,0,sizeof(a1));
memset(a2,0,sizeof(a2));
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
sort(s+1,s+n+1,cmp);
ll ans=0;
for (int i=1; i<=n; i++)
{
a1[s[i].x]++;//a1数组是用来表示每个位置有多少头牛
a2[s[i].x]+=s[i].x;//a2数组是用来表示每头牛的坐标,方便求解坐标和
add1(s[i].x,1);
add2(s[i].x,s[i].x);
ll nn=sum1(s[i].x);//个数
ll sss=sum2(s[i].x);//坐标
//cout<<111111<<endl;
ans+=(nn*s[i].x-sss)*s[i].f;//得到的是在当前x前面所有坐标小于他的牛,此时我们还需要找到在他前面的比他坐标值大的x
ll nnn=i-nn;
ll ss=sum2(20000)-sss;
ans+=(ss-s[i].x*nnn)*s[i].f;
}
printf ("%lld\n",ans);
}
return 0;
}