[題解]AT_abc274_f [ABC274F] Fishing

WaterSunHB發表於2024-06-23

思路

因為此題撒網的時間和位置都是未知的,所以必須列舉出一個。

又因為時間有可能是一個小數,不好列舉,因此考慮列舉位置。

首先,有一個顯然的貪心策略,每一次撒網的位置的左端點一定是一條魚。

那麼,我們不妨列舉撒網位置的左端點為第 \(i\) 條魚。

然後可以算出其餘的魚能被一起捕到的時間段。

那麼,問題就轉變為了,在一堆時間段中,取一個點,使得這個點所在的時間段的權值之和最大。

直接用差分維護一個即可。

Code

#include <bits/stdc++.h>  
#define re register  
  
using namespace std;  
  
const int N = 2010;  
const double eps = 1e-9;  
int n,len,ans;  
int w[N],x[N],v[N];  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
int main(){  
    n = read();  
    len = read();  
    for (re int i = 1;i <= n;i++){  
        w[i] = read();  
        x[i] = read();  
        v[i] = read();  
    }  
    for (re int i = 1;i <= n;i++){  
        map<double,int> mp;  
        int res = w[i];  
        for (re int j = 1;j <= n;j++){  
            if (i == j) continue;  
            if (v[i] == v[j]){//當 v[i] = v[j] 時,i 和 j 的相對位置不變,判斷 0 時刻能否被捕到即可   
                if (x[j] >= x[i] && x[j] - x[i] <= len) res += w[j];  
            }  
            else{  
                double l = 1.0 * (x[i] - x[j]) / (v[j] - v[i]);//算出左右端點   
                double r = 1.0 * (x[i] - x[j] + len) / (v[j] - v[i]);  
                if (r - l < eps) swap(l,r);  
                if (r >= 0){  
                    l = max(l,0.0);  
                    mp[l] += w[j];  
                    mp[r + eps] -= w[j];  
                }  
            }  
        }  
        ans = max(ans,res);  
        for (auto it = mp.begin();it != mp.end();it++){  
            res += it -> second;  
            ans = max(ans,res);  
        }  
    }  
    printf("%d",ans);  
    return 0;  
}