【10-25模拟赛T1】子集和

你有 \(n\) 个正整数 \(a_1,a_2,\cdots,a_n\),它们的和是 \(m\)。你想对他们的每个子集 \(S\),求出它们的和。

现在你得到了 \(2 ^ n\)\([0,m]\) 之间的和,其中数字 \(i\) 出现了 \(b\) 次。

现在给出数组 \(b\),请还原 \(a\) 数组。

显然,最小的满足 \(b_i > 0\)\(i\) 肯定在 \(a\) 中出现了 \(b_i\) 次,我们新建一个数组 \(f\) 维护当前集合中每个子集和的出现次数,我们暴力把 \(i\) 往集合里加 \(b_i\) 次(注意当前真实的 \(b_i\)\(b_i - f_i\)\(f_i\) 相当于 \(i\) 被从 \(b\) 中删除的次数)。

复杂度 \(O(能过)\)(有人能帮我分析一下吗)。

#include<bits/stdc++.h>
using namespace std;
const int N = 59,M = 10009;
int n,m;
int b[M],f[M];
void insert(int v) {
    for (int j = m;j >= v;j--)
        f[j] += f[j - v];
}
int main(){
    freopen("subset.in","r",stdin);
    freopen("subset.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin >> n >> m;
    for (int i = 0;i <= m;i++)
    	cin >> b[i];
    f[0] = 1;
    int cnt = 0;
    for(int i = 1;i <= m;i++){
        int val = b[i] - f[i];
        while(val--){
            insert(i);
            cout << i << ' ';
            if(++cnt == n)//不加这个会 TLE
            	return 0;
        }
    }
    return 0;
}
posted @ 2024-10-25 13:54  5t0_0r2  阅读(2)  评论(0编辑  收藏  举报