abc056d <贪心 / 二分+DP+bitset>

https://atcoder.jp/contests/abc056/tasks/arc070_b

solution1: 贪心

// https://atcoder.jp/contests/abc056/tasks/arc070_b
// 查到多种做法 二分 / dp ...
// 参考 https://blog.csdn.net/sdz20172133/article/details/90739645
// 这里是贪心做法
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 5e3 + 10;
int a[N];

void solv()
{
    int n, k;
    cin >> n >> k;

    for (int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + 1 + n);
    int pos = lower_bound(a + 1, a + 1 + n, k) - a - 1;
    int ans = pos;
    for (int i = 1; i <= pos; i++)
    {
        int s = 0;
        for (int j = pos; j; j--)
        {
            if (i == j || s >= k - a[j]) continue;
            s += a[j];
            if (s >= k - a[i])
            {
                ans --;
                break;
            }
        }
    }
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--)
    {
        solv();
    }
    return 0;
}

solution2: DP

注意这种DP的属性值为bool值的情况, 使用bitset优化效果极佳!
bitset使用+DP优化案例参考传送门

// https://atcoder.jp/contests/abc056/submissions/me
// 二分 + DP + bitset优化DP
// check0 为不用bitset优化的DP,
// check1 为使用bitset的DP, 
// 二者耗时实测相差约30倍

#include <iostream>
#include <algorithm>
#include <vector>
#include <bitset>
using namespace std;
typedef long long LL;
const int N = 5e3 + 10;
int a[N];
int n, k, pos;

// DP进行检查
// 1058ms, 6524KB
bool check0(int x)
{
    if (a[x] >= k) return true;
    // 检查 a[1~pos] 除去 a[x] 外, 能否凑出 k-a[x] ~ k-1 中的数,
    // 如果可以, 则 a[x] 为必须的元素, 反之不必须(返回false)
    vector<vector<bool>> f(pos+1, vector<bool>(k+1, false));
    f[0][0] = true;
    // 考虑前i个元素(不含第x个), 能否凑出数字j
    for (int i = 1; i <= pos; i ++)  
    {
        for (int j = 0; j < k; j ++)
        {
            f[i][j] = f[i][j] | f[i-1][j];
            if (j >= a[i] && i != x) f[i][j] = f[i][j] | f[i-1][j-a[i]];
        }
    }
    // 检查dp结果
    for (int i = k-a[x]; i < k; i ++) if (f[pos][i]) return true;  // 必须
    return false;  // 非必需
}

// 用bitset对DP进行优化
// 理论上将时间复杂度 /32, 实测也确实如此
// 31ms, 3656KB
bool check1(int x)
{
    if (a[x] >= k) return true;
    bitset<N*2> f;  // 默认初始化每位都为0
    f.set(0);  // 令f[0] = 1;

    // 仅使用1维, 这是对check0中的dp的滚动优化
    // 因为这里的bitset是将 N*2 位同时进行操作的, 因而也无需备份
    // 注意更新顺序与check0不同, 这里展开写成check0的形式是 f[i][j+a[i]] |= f[i-1][j] ,
    // 不过因为bitset的运算, 可以直接将j这一维度同时进行计算, 也就是用 ' <<a[i] ' 表示了 ' +a[i] '
    for (int i = 1; i <= pos; i ++)
        if (i != x)
            f |= f << a[i];
    // 检查dp结果
    for (int i = k-a[x]; i < k; i ++) if (f[i]) return true;
    return false;
}

void solv()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    sort(a+1, a+1+n);
    // 找到 a[i] >= k 的位置, 这样的a[i]一定是必须的
    pos = lower_bound(a+1, a+1+n, k) - a;

    int l = 1, r = pos;
    // 找到第一个必要的元素 [... , 其左侧均为非必要元素
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (check1(mid)) r = mid;
        else l = mid + 1;
    }
    int ans = l - 1; // a[l~n] 为必须元素, 因而非必需元素为 a[1~l-1]
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T --)
    {
        solv();
    }
    return 0;
}
posted @   O2iginal  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示