[lnsyoj3174/luoguP4823/TJOI2013]拯救小矮人

题意

给定序列 a,b 和常数 h,若序列中存在值 k 满足 bk+i=1len(a)aih,则可将 ak,bk 删除,求从 a 中删除的数的数量最大为多少。

sol

由于 b 越小的数越靠后越难被删除,同时,a 越大的数越可以帮助其他数字被删除,因此我们希望先被删除的数的 a,和 b 都更小,因此我们按照 a+b 来进行排序,然后进行一次 DP,计算前 i 个值中,被删掉 j 个值剩下的所有值的 ai 为多少。此时,若该值 DP 值非负,说明这是一个合法状态,因此倒序枚举,若 DP 值非负,则直接输出即可。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define x first 
#define y second 

using namespace std;
typedef pair<int, int> PII;

const int N = 2005;

PII a[N];
int n, h;
int f[N][N];

bool cmp(PII a, PII b){
    if (a.x + a.y != b.x + b.y) return a.x + a.y < b.x + b.y;
    return a.x < b.x;
}

int main(){
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) scanf("%d%d", &a[i].x, &a[i].y);
    scanf("%d", &h);
    sort(a + 1, a + n + 1, cmp);
    
    memset(f, -0x3f, sizeof f);
    for (int i = 0; i <= n; i ++ ) {
        f[i][0] = 0;
        for (int j = 1; j <= n; j ++ ) 
            f[i][0] += a[j].x;
    }

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ ) {
            f[i][j] = f[i - 1][j];
            if (f[i - 1][j - 1] + a[i].y >= h) f[i][j] = max(f[i][j], f[i - 1][j - 1] - a[i].x);
        }

    // for (int i = 0; i <= n; i ++ ) printf("%d\n", f[n][i]);

    for (int i = n; i >= 0; i -- )
        if (f[n][i] >= 0) {
            printf("%d\n", i);
            return 0;
        }

}
posted @   是一只小蒟蒻呀  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示