牛客網題集——張經理的員工(數學邏輯思維)

張經理的員工

張經理的公司的辦公室長達100000米,從最左端開始每間隔1米都有一個工位(從第1米開始有工位),位於第i米的工位稱爲i號工位,且這些工位都在一條水平線上。他有n個員工,每個員工分別位於xi號工位上(不同員工可能位於同一個工位)。
現在張經理想把員工聚集在某兩個工位上,他有q套方案(每套方案包含兩個工位號,兩個工位號可能相同),他想知道對於每套方案,所有員工都到達兩個工位中的某一個所需走的最短路徑之和是多少。
輸入描述:
第一行輸入兩個正整數n, q
第二行輸入n個正整數xi,分別代表第i個員工的工位
之後q行每行輸入兩個整數a,b,代表該套方案要求的兩個集合位置
(1<=n,q,xi,a,b<=105)(1<=n,q,xi,a,b<=105)
輸出描述:
對於每套方案,輸出一個整數代表答案,每個答案獨佔一行。
示例1
輸入
3 2
1 3 5
1 4
2 1
輸出
2
4
題目來源牛客網


題意

張經理有n個員工,每個員工分別位於xi號工位上(不同員工可能位於同一個工位)。
現在張經理想把員工聚集在某兩個工位上,他有q套方案(每套方案包含兩個工位號,兩個工位號可能相同),他想知道對於每套方案,所有員工都到達兩個工位中的某一個所需走的最短路徑之和是多少?

解題思路

每種方案都給出了a、b兩個聚集工位。在題目中,查詢次數 q 最大爲1e5,所以在每次查詢時間複雜度不能高於log級別,每次查詢給出的a和b。

最短路徑中有三種情況:
(一)、位於 a 左邊的員工應該前往 a 。
(二)、位於 b 右邊的員工應該前往 b 。
(三)、位於a、b之間的工位若相比於到 b 的距離,該工位距離 a 較近則前往 a ,否則前往 b 。

關鍵點:統計出每一個工位上的員工,並提取有用信息。
步驟一、預處理——方便快速查詢出結果
①、數組Y記錄每個工位上的員工人數,用下標來表示不同工位。
②、統計小於等於i位置的員工個數,記錄在數組min_i。
③、統計小於等於i位置的員工下標之和,記錄在數組min_i_sum。
④、統計大於等於i位置的員工個數,記錄在數組max_i。
⑤、統計大於等於i位置的員工下標之和,記錄在數組max_i_sum。

步驟二、計算方式
①、小於等於a工位每個員工的總距離:x = min_i_sum[a] * a - min_i[a]。
②、大於等於b工位每個員工的總距離:y = max_i[b] - max_i_sum[b] * b。
③、若b-a>1,則a與b之間存在工位。
創建變量c=(a+b)/2,劃分更近a與更近b的工位。
a~c員工的最短位移:z = min_i[c] - min_i[a] - (min_i_sum[c] - min_i_sum[a]) * a。
c~b員工的最短位移: w = b * (min_i_sum[b] - min_i_sum[c]) - (min_i[b] - min_i[c])。
(可包含a、b工位員工,因爲它們到自身的距離爲0,不影響結果)

步驟三、得出答案
最終答案:x + y + z + w。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100005;
ll X[maxn] , Y[maxn];
ll min_i[maxn] , min_i_sum[maxn];
ll max_i[maxn] , max_i_sum[maxn];
int main()
{
    int n,q;
    cin>>n>>q;
    
    //避免a與b上無工位的情況 
    for(int i=1;i<=n;i++)
	{
        scanf("%d",&X[i]);
        Y[X[i]]++;	//每個工位上的員工數量 
    }
    ll sum = 0,sum2 = 0;
    //i距離起點長度 
    for(int i=1; i<=100000; i++)
	{
        if(Y[i])
		{
            sum += i * Y[i];
            sum2 += Y[i];
        }
        //小於等於i位置的員工個數 
        min_i[i] = sum;
        //小於等於i位置的員工下標之和
        min_i_sum[i] = sum2;
    }
    sum = 0,sum2 = 0;
    for(int i=100000; i>=1; i--)
	{
        if(Y[i]){
            sum += i * Y[i];
            sum2 += Y[i];
        }
        //大於等於i位置的員工個數
        max_i[i] = sum;
        //大於等於i位置的員工下標之和 
        max_i_sum[i] = sum2;
    }
    while(q--)
	{
        int a, b;
        ll ans = 0;
        scanf("%d %d",&a,&b);
        if(a > b)
            swap(a , b);
        
        ll x, y, z=0, w=0;
        //1~a員工的最短位移 
        x = min_i_sum[a] * a - min_i[a];
        //b~n員工的最短位移 
        y = max_i[b] - max_i_sum[b] * b;
        
        //若a與b之間有工位
        if(b - a > 1)
		{
            int c = (b+a)/2;
            //a~c員工的最短位移 
            z = min_i[c] - min_i[a] - (min_i_sum[c]-min_i_sum[a]) * a;
            //c~b-1員工的最短位移 
            w = b * (min_i_sum[b]-min_i_sum[c]) - (min_i[b]-min_i[c]);
        }
        
        cout<<x + y + z + w<<endl;
    }
     return 0;
}

總結

該題關鍵在於由題目得到更多有用的信息,讓我們能夠通過它們之間的關係快速計算出正確的答案,有效的避免時間複雜度過大。
參考題解

希望能夠將自己的一些學習經驗分享給有需要的人。
我是小鄭,一個堅持不懈的小白

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章