AcWing 532.货币系统(完全背包统计最大无关组个数)

开篇点题:参考彩笔大佬的题解!

题目分析:

给定一个集合   (n,a)    ------------- 表示给定n个a[i]                                                                            求出一个集合(m,b)   -------------- 表示所求的m个b[j],使得每个a[i]都可以被b[j]表示,并且也可以表示所有通过a数组线性表示的值,同时也可由m个数表示。

通过题目所说表示数的方式,可以推断出是完全背包的做法。(即用无限个可用物品承装体积)

比较困难的是部分线性代数知识:

通过大一上学期学过的线性代数,

我们可以通过k = x1a1 + x2a2 + x3a3 + x4a4 ······ + xnan (任意x >= 0且不同时为0)来表示所能表示的整数集。如果a[i]中的某个数可以被更小的k(其他的整数表示),则该a[i]是无用的,因此我们只需求出最大无关组,使得每个a都可以被更小的m表示出来即可

那如何求向量组 (a1,a2,⋯,an) 的 最大无关向量组?

利用数论中素数筛的思路,对于一个较大的a[i],如果出现重复,一定会被较小的a[i]删掉。

则我们首先进行排序:

从小到大,先查看当前数有没有被晒掉,

1)如果没有就把它加入到最大无关向量组中,并把他以及他和此前的硬币的线性组合都筛掉
2)如果有就不理会
3)即就是在完全背包求方案数的过程中,统计那些初始没有方案数的物品

因此就是一个筛的写法!

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

int a[N];
int f[N];//考虑前i个物品,当前体积为j的方案
void solve()
{
    int n;
    cin >> n;   
    for(int i  = 0; i < n; i ++) cin >> a[i];
    sort(a,a+n);
    int m = a[n - 1];
    int res = 0;
    memset(f, 0, sizeof f);
    f[0] = true;//一个不选,0可以被表示
    for(int i = 0; i < n; i ++)
    {
        if(f[a[i]]) continue;
        else res ++;
        for(int j = a[i]; j <= m; j ++)
        {
            f[j] |= f[j - a[i]];
        }
    }
    cout << res << endl;

}
int main()
{
    int t;
    cin >> t;
    while(t --)
    solve();



    system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值