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;

}
```

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

时间: 2024-11-12 11:24:53

Codeforces Round #544 (Div. 3) dp + 双指针的相关文章

D. XOR-pyramid Codeforces Round #483 (Div. 2) dp

题目链接:D. XOR-pyramid 题解:dp[i][j]表示以j开始长度为i的串的f()值,转移方程就很简单了dp[i][j]=(dp[i-1][j]^dp[i-1][j+1]); 然后求的是字段的最大值,用an数组维护dp的最大值就可以了. #include<bits/stdc++.h> #define ll long long #define ull unsigned long long using namespace std; const int maxn=5e3+5; const

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

You are a coach at your local university. There are n n students under your supervision, the programming skill of the i i -th student is a i ai . You have to create a team for a new programming competition. As you know, the more students some team ha

Codeforces Round #544 (Div. 3) D

题目链接:D. Zero Quantity Maximization #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define LL long long #define pii pair<LL,LL> map<pair<LL,LL>,LL>mp,mpp; LL a[maxn],b[maxn]; LL gcd(LL a,LL b){ return b?gcd(b,a%b)

CodeForces Round #544 Div.3

A. Middle of the Contest 代码: #include <bits/stdc++.h> using namespace std; int h1, m1, h2, m2; int tim1 = 0, tim2 = 0; int main() { scanf("%d:%d", &h1, &m1); scanf("%d:%d", &h2, &m2); tim1 = h1 * 60 + m1; tim2 = h

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

DP Codeforces Round #303 (Div. 2) C. Woodcutters

题目传送门 1 /* 2 题意:每棵树给出坐标和高度,可以往左右倒,也可以不倒 3 问最多能砍到多少棵树 4 DP:dp[i][0/1/2] 表示到了第i棵树时,它倒左或右或不动能倒多少棵树 5 分情况讨论,若符合就取最大值更新,线性dp,自己做出来了:) 6 */ 7 #include <cstdio> 8 #include <algorithm> 9 #include <cstring> 10 #include <cmath> 11 #include &

Codeforces Round #267 (Div. 2) C. George and Job(DP)补题

Codeforces Round #267 (Div. 2) C. George and Job题目链接请点击~ The new ITone 6 has been released recently and George got really keen to buy it. Unfortunately, he didn't have enough money, so George was going to work as a programmer. Now he faced the follow

Codeforces Round #260 (Div. 1) A. Boredom (DP)

题目链接:http://codeforces.com/problemset/problem/455/A A. Boredom time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Alex doesn't like boredom. That's why whenever he gets bored, he comes up with

Codeforces Round #433 (Div. 1) D. Michael and Charging Stations(dp)

题目链接:Codeforces Round #433 (Div. 1) D. Michael and Charging Stations 题意: 一个人每天要加油,1种为1000,1种为2000,如果付全额,会得到10%的回扣放在卡上. 如果卡上有剩余的回扣,可以拿来抵现金.问n天最少需要花多少钱. 题解: 很直观的一个dp就是考虑dp[i][j],表示第i天卡上剩余回扣为j的最小花费. 将所有的数除以100后,j其实是小于40的,严格的说是小于30,官方题解有个证明. 因为卡上不可能积累很多的