张经理的员工 前缀和

题目链接: https://ac.nowcoder.com/acm/contest/5403/A

本来只是给校赛作为一个简单题,没想到杀疯了orz(通过率只有不到5%
捕获.PNG

不知道为啥暴力复杂度达到了1e10还有这么多人敢冲

用两个数组分别储存员工数目的前缀和以及员工坐标的前缀和,记为sum1和sum2。

对于一套方案中的两个工位a,b(假设a<b),令mid=(a+b)/2,易知在[1,mid]范围内的员工到a点更近,在[mid+1, 105]范围内的员工到b点更近。

对于要到a的员工,分为不在a的右侧和在a的右侧两类。

//计算不在a右侧要到a的员工的答案(即在[1,a]内的员工
ans+=sum1[a]*a-sum2[a];
//计算在a右侧要到a的员工的答案(即在[a+1,mid]内的员工
ans+=(sum2[mid]-sum2[a])-(sum1[mid]-sum1[a])*a

要到b的员工同理,加起来就可以得到答案了。

std:

#include <bits/stdc++.h>
#define N 100000
using namespace std;
typedef long long ll;

ll n, q, ans;
ll sum1[N+10], sum2[N+10];

int main()
{
    cin>>n>>q;
    for (int i=1, x; i<=n; i++)
    {
        cin>>x;
        sum1[x]++, sum2[x]+=x;
    }
    for (int i=1; i<=N; i++)
        sum1[i]+=sum1[i-1], sum2[i]+=sum2[i-1];
    for (int i=1, a, b, mid; i<=q; i++)
    {
        cin>>a>>b;
        if (a>b) swap(a, b);
        ans=0, mid=(a+b)/2;
        ans+=sum1[a]*a-sum2[a];//[1,a]
        ans+=sum2[mid]-sum2[a]-(sum1[mid]-sum1[a])*a;//[a+1,mid]
        ans+=(sum1[b]-sum1[mid])*b-(sum2[b]-sum2[mid]);//[mid+1, b]
        ans+=sum2[N]-sum2[b]-(sum1[N]-sum1[b])*b;//[b+1, N]
        cout<<ans<<"\n";
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/opppppppp/p/12817564.html