zoukankan      html  css  js  c++  java
  • [USACO04OPEN]MooFest

    题目

    Description

    约翰的N 头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出max{Vi; Vj}×|Xi − Xj | 的音量,其中Vi 和Vj 分别是第i 头和第j 头奶牛的听力。

    假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

    Input

    • 第一行:单个整数N,1 ≤ N ≤ 20000

    • 第二行到第N + 1 行:第i + 1 行有两个整数Vi 和Xi,1 ≤ Vi ≤ 20000; 1 ≤ Xi ≤ 20000

    Output

    • 单个整数:表示所有奶牛产生的音量之和

    Sample Input

    4
    3 1
    2 5
    2 6
    4 3

    Sample Output

    57

    思路

    首先肯定想到按坐标先排序;

    我们可以枚举每个点假设作为 $max(v[i],v[j])$ 较大的那一个;

    然后用树状数组分别找出前面 $leq v[i]$ 的牛 和 后面  $leq v[i]$ 小的牛;

    分别加上音量即可;

    那么求距离需要开两个树状数组,一个存 $leq v[i]$ 的个数,另一个存 $leq v[i]$ 的坐标和;

    $i$ 与所有点的距离和就是 ,个数$ imes v[i]$ $-$ 坐标和 ;

    注意这里有个魔鬼细节:

    可能会出现了重复的 $v[i]$ ;

    假设两个点坐标是 $i$ ,$j$ $( i leq j)$;

    这样可能导致找前面 $leq v[j]$ 时计算了一遍了 $v[i]$ ; 找后面 $leq v[i]$ 时计算了一遍 $v[j]$ ;

    那么解决的话,就在找前面 或 找后面时 改成求 $<v[i]$ 就可以了;

    写完后,我看了一下其他巨佬的题解;

    写法不太一样,瞬间觉得我的写法弱爆了;

    代码

    #include<bits/stdc++.h>
    #define re register
    typedef long long ll;
    using namespace std;
    inline ll read()
    {
        ll a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    ll n;
    ll mx=-1;
    struct ljj
    {
        ll x,v;
    }a[50010];
    struct ljq
    {
        ll w,num;
    }sum[50010];
    inline ll lowbit(ll x)
    {
        return x&(-x);
    }
    inline void insert(ll x,ll y)
    {
        while(x<=mx)
        {
            sum[x].w+=y;
            x+=lowbit(x);
        }
    }
    inline ll findout(ll x)
    {
        ll s=0;
        while(x)
        {
            s+=sum[x].w;
            x-=lowbit(x);
        }
        return s;
    }
    inline void add(ll x,ll y)
    {
        while(x<=mx)
        {
            sum[x].num+=y;
            x+=lowbit(x);
        }
    }
    inline ll find(ll x)
    {
        ll s=0;
        while(x)
        {
            s+=sum[x].num;
            x-=lowbit(x);
        }
        return s;
    }
    inline ll cmp(ljj a,ljj b)
    {
        if(a.x==b.x)
            return a.v<b.v;
        else
            return a.x<b.x;
    }
    int main()
    {
        n=read();
        for(re ll i=1;i<=n;i++)
        {
            a[i].v=read();
            a[i].x=read();
            mx=max(a[i].v,mx);
        }
        sort(a+1,a+n+1,cmp);//按坐标排序 
        ll ans=0;
        for(re ll i=1;i<=n;i++)
        {
            ll sum=findout(a[i].v);//计算前面小于等于 v[i] 的坐标和 
            ll t=find(a[i].v);     //找小于等于 v[i] 的个数 
            insert(a[i].v,a[i].x);
            add(a[i].v,1);
            ans+=abs(t*a[i].x-sum)*a[i].v; //所有坐标相减 乘以 v[i] 
        }
        memset(sum,0,sizeof(sum));
        for(re ll i=n;i>=1;i--)
        {
            ll sum=findout(a[i].v-1);//计算后面小于 v[i] 的坐标和 
            ll t=find(a[i].v-1);     //找小于 v[i] 的个数 
            insert(a[i].v,a[i].x);
            add(a[i].v,1);
            ans+=abs(t*a[i].x-sum)*a[i].v; //所有坐标相减 乘以 v[i] 
        }
        printf("%lld
    ",ans);
        //return 0; 
    }
  • 相关阅读:
    【codevs4919】线段树练习4
    【51Nod1405】树上距离和 二次扫描与换根法
    【洛谷P1717】钓鱼
    【洛谷P1230】智力大冲浪
    【洛谷P1248】加工生产调度
    hdu 1195(搜索)
    hdu 1181(Floyed)
    hdu 1250(大整数)
    hdu 1180(广搜好题)
    hdu 1099(数学)
  • 原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/13869715.html
Copyright © 2011-2022 走看看