# Sliding Window# Prefix Sum# Greedy

c782 - PC. 孤單值量測

🔗 前往 ZeroJudge 原題

題目描述

題目要求計算一條馬路上 n 個人之間的孤單值總和。如果第 i 個人和第 j 個人的位置相差大於 k 公尺,則他們會對總孤單值 S 貢獻 w_i * w_j。

解題思路

這題的核心在於有效地計算所有滿足位置差大於 k 的配對 (i, j) 的 w_i * w_j 貢獻。直接使用兩層迴圈計算時間複雜度為 O(n^2),對於 n <= 2000000 的輸入會超時。

程式碼使用了一個 sliding window 的技巧來優化計算。對於每個位置 i,它找到一個最左邊的位置 s,使得 a[i] - a[s] > k。然後,它知道對於位置 i,只有位置 1 到 s-1 的人與位置 i 的距離大於 k。因此,它只需要計算位置 i 和位置 1 到 s-1 的人的貢獻。

為了加速計算 w_i * w_j 的總和,程式碼使用了 prefix sum 的技巧。w[i] 儲存了 w[1] 到 w[i] 的總和。這樣,計算 w[v[i]] * w[i] 的貢獻時,實際上是在計算 w[1] 到 w[v[i]] 的總和乘以 w[i]。

複雜度分析

  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

程式碼

#pragma GCC optimize(3)
#include <stdio.h>
#define MAX 2000001
#define BUFMAX 1048576
long long sum, w[MAX];
int kase, n, k, length = BUFMAX, a[MAX], v[MAX];
char buf[BUFMAX], tmp, * pt = buf, * end = buf;
inline char freadChar(){
    if (pt == end){
        if (length < BUFMAX)return EOF;
        length = fread(buf, 1, BUFMAX, stdin);
        end = buf + length;
        pt = buf;
    }
    return *pt++;
}
inline void freadUInt(int* val){
    while ((tmp = freadChar()) < '0')if (tmp == EOF) return;
    for(*val = tmp - '0';(tmp = freadChar()) >= '0';* val = (*val << 3) + (*val << 1) + (tmp - '0'));
}
inline void freadLongLong(long long* val){
    while ((tmp = freadChar()) < '-')if (tmp == EOF) return;
    if (tmp == '-'){
        for(*val = freadChar() - '0';(tmp = freadChar()) >= '0';* val = (*val << 3) + (*val << 1) + (tmp - '0'));
        *val = -*val;
    }
    else{
        for(*val = tmp - '0';(tmp = freadChar()) >= '0';* val = (*val << 3) + (*val << 1) + (tmp - '0'));
    }
}
int main(){
    for(scanf(" %d", &kase);kase--;printf("%lld\n", sum)){
        sum = 0;
        freadUInt(&n), freadUInt(&k);
        for (int i = 1; i <= n; )freadUInt(&a[i++]);
        for (int i = 1, s = 1; i <= n; ++i){
            for(;a[i] - a[s] > k;++s);
            v[i] = s - 1;
        }
        for (int i = 1; i <= n; ++i){
            freadLongLong(&w[i]);
            sum += w[v[i]] * w[i];
            w[i] += w[i - 1];
        }
    }
}

Discussion