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组的最大值
- 两个转移方向
- 不选 dp[i-1][j] -> dp[i][j]
- 和前面的分组 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)