题意
给出N头牛,每头牛因为哞(hu)声(xiang)太(shang)大(hai)而有了一个耳背值v,它们在x轴上排成一排,每头牛有一个坐标x(v,x,n<20000,没有两头牛有相同的x),如果两头牛要对话,音量为它们之间的距离abs(x[i]-x[j])*max(v[i],v[j]),求每两头牛都互相对话的音量总和(不要问我为什么它可以同时跟n-1头牛说话,我还在压牛顿的棺材板,忙得很)
分析
想n^2卡过去的,这是2004的题。
首先的一步操作是按照v值从小到大排序,然后按顺序处理,这样的话,当前这个牛与之前所有牛相比,耳背值都是取这个牛,这样就可以把之前的牛成坨处理。这是一个老套路了,在有多个关键字而且答案与下表无关的题中,常常会按照某个关键字排序,来简化问题。
接下来是如何处理v值小于等于它这一坨牛的问题,用树状数组(或线段树)来维护,存小于等于当前x值的牛数和这些牛的x值之和,这样做的话,每次处理一头牛,直接就可以求出x小于它的牛与它距离和=牛数*该牛的x值-那些牛的x之和,同理求出x大于它的牛与它距离和,然后两者加起来,乘以该牛的v,加入ans即可。这样处理完后,再将这头牛加入树状数组。
这道题主要的操作是排序以及想到将距离合在一起处理,想清楚了就觉得比较简单。
代码
#include<cstdio>
#include<algorithm>
#define MAXN 20006
using namespace std;
long long bit[MAXN][2],ans;
int n;
struct node
{
long long v,x;
}cow[MAXN];
bool cmp(node a,node b)
{
return a.v<b.v;
}
inline long long lowbit(long long x)
{
return x&(-x);
}
long long addup(long long x,int op)
{
long long sum=0;
while(x)
{
sum+=bit[x][op];
x-=lowbit(x);
}
return sum;
}
void change(long long x,int op,long long d)
{
while(x<MAXN)
{
bit[x][op]+=d;
x+=lowbit(x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&cow[i].v,&cow[i].x);
sort(cow+1,cow+1+n,cmp);
for(int i=1;i<=n;i++)
{
long long scow=addup(cow[i].x,1);
long long sx=addup(cow[i].x,0);
ans+=cow[i].v*(scow*cow[i].x-sx);
scow=i-1-scow;
sx=addup(MAXN-1,0)-sx;
ans+=cow[i].v*(sx-scow*cow[i].x);
change(cow[i].x,1,1);
change(cow[i].x,0,cow[i].x);
}
printf("%lld",ans);
}