`

poj 1990

 
阅读更多

题意:FJ有n头牛,排列成一条直线(不会在同一个点),给出每头牛在直线上的坐标x。另外,每头牛还有一个自己的声调v,如果两头牛(i和j)之间想要沟通的话,它们必须用同个音调max(v[i],v[j]),沟通起来消耗的能量为:max(v[i],v[j]) * 它们之间的距离。问要使所有的牛之间都能沟通(两两之间),总共需要消耗多少能量。
 
思路:树状数组。很好的一道题。把牛按x升序排列,然后:(很难表示清楚,囧...)
1:把沟通分成向左和向右,向左就是:v[右] > v[左],它们之间取右边牛的声调。
2:先求向左的总能量:运用2个树状数组,都以牛的声调做下标,arNum[]用于求某个声调范围内牛的数量,arDis[]用于求某个声调范围内牛的总距离(与起点0的总距离),这对于当前的牛(x,v)来说,用它的音调向左沟通消耗的总能量则为:v * 左边声调比它小的牛和它的距离差之和(sum(v-1, arNum)* sum(v-1, arDis))。
3:相同的道理求出向右的总能量。

 

代码如下:

#include<iostream>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
const int MAX = 20005;

struct data
{
    int x, w;
}cow[MAX];
int arNum[MAX], arDis[MAX];

bool cmp(data a, data b)
{
    return a.x < b.x;
}

void add(int i, int *ar, int w)
{
    while(i <= MAX-1)
	{
        ar[i] += w;
        i += lowbit(i);
    }
}

__int64 sum(int i, int *ar)
{
    __int64 ans = 0;
    while(i > 0)
	{
        ans += ar[i];
        i -= lowbit(i);
    }
    return ans;
}

int main()
{
    int n, i;
    __int64 preNum, preDis;
    scanf("%d", &n);
    for(i = 0; i < n; i ++)
        scanf("%d%d", &cow[i].w, &cow[i].x);
    sort(cow, cow + n, cmp);
    __int64 ans = 0;
    memset(arNum, 0, sizeof(arNum));          //  求向左的总能量。
    memset(arDis, 0, sizeof(arDis));
    for(i = 0; i < n; i ++)
	{
        preNum = sum(cow[i].w-1, arNum);
        preDis = sum(cow[i].w-1, arDis);
        ans += (preNum * cow[i].x - preDis) * cow[i].w;
        add(cow[i].w, arNum, 1);
        add(cow[i].w, arDis, cow[i].x);
    }
    memset(arNum, 0, sizeof(arNum));          //  求向右的总能量。
    memset(arDis, 0, sizeof(arDis));
    for(i = n-1; i >= 0; i --)
	{
        preNum = sum(cow[i].w, arNum);        //  这里不要用w-1,考虑了声调相等的情况。
        preDis = sum(cow[i].w, arDis);
        ans += (preDis - preNum * cow[i].x) * cow[i].w;
        add(cow[i].w, arNum, 1);
        add(cow[i].w, arDis, cow[i].x);
    }
    printf("%I64d\n", ans);
    return 0;
}

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics