1. 程式人生 > >Codeforces Round #544 (Div. 3) dp + 雙指針

Codeforces Round #544 (Div. 3) dp + 雙指針

題意 移動 deb ace 最大的 ++ bit pac test

https://codeforces.com/contest/1133/problem/E

題意

給你n個數(n<=5000),你需要對其挑選並進行分組,總組數不能超過k(k<=5000),每組數字差距不超過5,問最多能挑出多少數字

題解

  • 先排序,在進行dp,定義dp[i][j]為前i個數分成j組的最大值
  • 兩個轉移方向
    1. 不選 dp[i-1][j] -> dp[i][j]
    2. 和前面的分組 dp[lt[i]-1][j-1] -> dp[i][j]
  • 怎麽確定i前面的哪個點是最大的?
    • 選擇能和i分到一組的最前面的數

      因為選擇最前面的數可以降低前一組的上限

    • 用雙指針or單調隊列處理

雙指針板子

    for(l=r=n;l>=1;){
        if(l<=r){
           if(a[r]-a[l]<=5)
               lt[r]=l--;
           else lt[--r]=++l; //l++十分重要,因為可能新的l和新的r不合適,這樣就r就會繼續向左移動,原來的r並沒有找到和他合適的l
        }else lt[r]=--l;
    }

代碼

include<bits/stdc++.h>

define M 5005

using namespace std;
long long a[M],n,k,i,j,p,ans=0,dp[M][M],lt[M],l,r;

int main(){
cin>>n>>k;
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
lt[i]=i;
}
sort(a+1,a+n+1);

for(l=r=n;l>=1;){
    if(l<=r){
       
       if(a[r]-a[l]<=5)
           lt[r]=l--;
       else lt[--r]=++l;
    }else lt[r]=--l;
}
for(i=1;i<=n;i++){
    for(j=1;j<=min(k,n);j++){
        p=lt[i];
        dp[i][j]=max(dp[i-1][j],dp[p-1][j-1]+i-p+1);
        ans=max(dp[i][j],ans);
    }
}
cout<<ans;

}
```

Codeforces Round #544 (Div. 3) dp + 雙指針