1. 程式人生 > 其它 >E. Pencils and Boxes 題解(雙指標+dp)

E. Pencils and Boxes 題解(雙指標+dp)

題目連結

題目大意

你有 n 只鉛筆,每個鉛筆的飽和度是 a[i]。

現在你要把鉛筆放進盒子裡,盒子可以有任意個,但是每個盒子裡至少要放 k 只鉛筆。

並且對於一個盒子裡任意兩隻鉛筆 i 和 j 必須滿足他們的飽和度差異不超過 d

即 |a[i] - a[j]| ≤ d問是否存在一種可行的放法。

1 ≤ k ≤ n ≤ 500000, d, a[i] ≤ 10^9

題目思路

其實仔細思考是一個很簡單的dp

顯然我們發現把 a 數列排序後按順序劃分一定是最優的。

因此我們可以先對 a 數列從小到大排序,然後用 \(dp[i]\)表示能否把前 i 個放進盒子裡

然後再用雙指標和字首和優化下dp即可

程式碼

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=5e5+5,inf=0x3f3f3f3f,mod=1234567891;
const double eps=1e-6;
int n,k,d;
int a[maxn];
int dp[maxn],pre[maxn];
bool ask(int l,int r){
    if(r<l){
        return 0;
    }else if(l<=0){
        return pre[r]>0;
    }else{
        return pre[r]-pre[l-1]>0;
    }
}
signed main(){
    scanf("%d%d%d",&n,&k,&d);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    int l=0;
    dp[0]=1;
    pre[0]=1;
    for(int i=1;i<=n;i++){
        while(a[i]-a[l]>d) l++;
        dp[i]=ask(l-1,i-k);
        pre[i]=pre[i-1]+dp[i];
    }
    printf(dp[n]?"YES\n":"NO\n");
    return 0;
}

卷也卷不過,躺又躺不平