AtCoder Beginner Contest 216(F)

文章介绍了F-MaxSumCounting问题,即给定两个等大小的序列a和b,要求找出满足max(ai)>∑bi的子集方案数。由于三重循环的高复杂度不适用于n=5000的情况,文章提出先对序列a排序,然后转化为普通背包问题求解方案数,降低了时间复杂度。代码示例展示了如何实现这一方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

F - Max Sum Counting

链接: F - Max Sum Counting

题意

两个 大小为 n n n 的序列 a i ai ai b i bi bi,任意选取一些下标 i i i,求 max ⁡ ( a i ) > = ∑ b i \max(ai) >= \sum{bi} max(ai)>=bi的方案数。

解析

首先考虑状态 一是和, 二是最大值, 但这样我们发现需要三重循环,在 n = 5000 n = 5000 n=5000 的情况下是不能接受的复杂度,于是我们想到按 a i ai ai 排序后,我们只计算 ∑ b i \sum{bi} bi 的方案,将所有满足条件的方案再计入答案,就变成一个普通的背包求方案数了。

对于要按 a i ai ai 排序的证明:
因为我们没有多开一维来记录 max ⁡ ( a i ) \max(ai) max(ai) 最大值, 所以对于每一种 b i bi bi 和为 s u m sum sum 他的状态集合可能有许多不同的 m a x ( a i ) max(ai) max(ai)
假设和为 s u m sum sum m a x ( a i ) = a j max(ai) = aj max(ai)=aj m a x a i = a k max{ai} = ak maxai=ak 两种可能,若是不按 a i ai ai 排序 会导致不知道 a j , a k aj, ak aj,ak 那种状态可以转移

假设 s u m = 10 sum = 10 sum=10 a j = 100 aj = 100 aj=100 a k = 10 ak = 10 ak=10 当前的 a i = 10 ai = 10 ai=10 b i = 10 bi = 10 bi=10 那么只能从 a j aj aj 转移 因为只有这种才保证 max ⁡ ( a i ) > ∑ b i \max(ai) > \sum{bi} max(ai)>bi 但已经把 a j , a k aj, ak aj,ak 的状态整合在一起了不能分开。
若是按 a i ai ai 排序,新来的 a i ai ai 一定是目前的最大值, 一定比 a j aj aj a k ak ak 都大 于是一个状态包含的所有情况都能转移。

代码

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5010, mod = 998244353, MAX = 5000;
struct node{
    int ai, bi;
    bool operator < (const node &A)const{
        return ai < A.ai;
    }
}s[N];
int f[N];//bi之和价值为i的方案数
int main(){
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> s[i].ai;
    for(int i = 1; i <= n; i ++) cin >> s[i].bi;
    sort(s + 1, s + 1 + n);

    f[0] = 1;
    int ans = 0;
    for(int i = 1; i <= n; i ++){
        for(int j = MAX; j >= s[i].bi; j --){
            f[j] = (f[j] + f[j - s[i].bi]) % mod;
            if(j <= s[i].ai) ans = (ans + f[j - s[i].bi]) % mod;
        }
    }
    cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值