码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-03-09 20:17:17      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:code   min   scan   its   names   int   force   超过   include   

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 + 双指针

标签:code   min   scan   its   names   int   force   超过   include   

原文地址:https://www.cnblogs.com/VIrtu0s0/p/10502722.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!