Codeforces Round #544 (Div. 3) dp + 双指针

Posted virtu0s0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #544 (Div. 3) dp + 双指针相关的知识,希望对你有一定的参考价值。

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 + 双指针的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #544 (Div. 3) C. Balanced Team [暴力剪枝]

Codeforces Round #544 (Div. 3) dp + 双指针

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

背包DP || Codeforces 544C Writing Code

Codeforces Round #726 (Div. 2) B. Bad Boy(贪心)