【无码专区12】子集和(背包dp)
此題已自我實(shí)現(xiàn),但仍歸于無碼專區(qū)
本題在考場上就過了,所以難度并不高,發(fā)現(xiàn)性質(zhì)即可。
problem
有 nnn 個正整數(shù) a1,a2,...,ana_1,a_2,...,a_na1?,a2?,...,an?,他們的和為 mmm。你想對于其每一個子集 SSS,求出他們的和。
給定 2n2^n2n 個 [0,m][0,m][0,m] 之間的和,其中數(shù)字 iii 出現(xiàn)了 bib_ibi? 次。
求還原 aaa,數(shù)據(jù)保證有唯一解。
n≤50,m≤10000,1s,128MBn\le 50,m\le 10000,1s,128MBn≤50,m≤10000,1s,128MB
my idea
首先就能知道 b0,bmb_0,b_mb0?,bm? 一定是 111。
馬上就發(fā)現(xiàn)最小的 aia_iai? 是沒有能被其他數(shù)組合出來的情況的,因?yàn)樗麄內(nèi)钦龜?shù)!
所以最小的 bi≠0b_i\neq 0bi??=0 的 iii,就意味著 aaa 中原來有 bib_ibi? 個 iii。
然后考慮第二小的 bj≠0b_j\neq 0bj??=0 的 jjj,會注意到有可能 bib_ibi? 個 iii 可能會組合出 jjj。
減去這些組合就是 aaa 中原本有 bj′b_j'bj′? 個 jjj。
發(fā)現(xiàn)這就是個背包 dpdpdp 的過程。
容量 mmm,但最多只會背包 nnn 次。
所以跑得很快。
solution
與我的想法相同。
每次找到子集中最小的元素,也就是最小的 bib_ibi? 不等于 000 的 iii,然后從背包里刪去即可。
刪除就是可以理解成逆向執(zhí)行一下背包中加入元素 xxx 的操作,也就是從小到大,執(zhí)行 bi?=bi?xb_i-=b_{i-x}bi??=bi?x?。
code
#include <bits/stdc++.h> using namespace std; #define maxn 55 #define maxm 10005 #define int long long int n, m, cnt; int b[maxm], a[maxn], f[maxm]; int c[maxn][maxn];signed main() {freopen( "subset.in", "r", stdin );freopen( "subset.out", "w", stdout );scanf( "%lld %lld", &n, &m );for( int i = 0;i <= n;i ++ ) {c[i][0] = c[i][i] = 1;for( int j = 1;j < i;j ++ )c[i][j] = c[i - 1][j - 1] + c[i - 1][j];}for( int i = 0;i <= m;i ++ ) scanf( "%lld", &b[i] );f[0] = 1;for( int i = 1;i <= m;i ++ ) {b[i] -= f[i];if( ! b[i] ) continue;for( int j = 1;j <= b[i];j ++ ) a[++ cnt] = i;for( int j = m;j;j -- ) {for( int k = 1;k <= b[i];k ++ )if( j < k * i ) break;else f[j] += f[j - k * i] * c[b[i]][k];}}for( int i = 1;i <= n;i ++ ) printf( "%lld ", a[i] );return 0; }總結(jié)
以上是生活随笔為你收集整理的【无码专区12】子集和(背包dp)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【无码专区11】异或2(结论 / 推式子
- 下一篇: 盲盒(随机概率 + 最大公约数)