【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;
}