【CF-687C】The Values You Can Make 01背包变形
C. The Values You Can Make
题意
给出n,k,以及n个数字,选取若干个数字组成k,在这若干个数字中选择一个子集,
问这个子集的和,可能的值有多少个。
题解
刚开始写的是01背包向前递推,然后写凉了。
是01背包的变形。
\(dp[i][j][k]\)表示在前i个数字中选取若干个数字,组成j的同时组成k是否可行。
\(dp[i][j][k]=max(dp[i-1][j-a[i]][l-a[i]],dp[i-1][j-a[i][l]]);\)
最后统计\(dp[n][k][i]==1\)的个数。
代码
#include<bits/stdc++.h>
#define pb push_back
typedef long long ll;
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 5e3+10;
int arr[N],dp[N][N];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++)
scanf("%d",&arr[i]);
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=k;j>=arr[i];j--)
{
for(int l=k;l>=0;l--)
{
dp[j][l]=max(dp[j][l],dp[j-arr[i]][l]);
if(l>=arr[i]) dp[j][l]=max(dp[j][l],dp[j-arr[i]][l-arr[i]]);
}
}
}
int ans=0;
for(int i=0;i<=k;i++)
{
if(dp[k][i])
ans++;
}
printf("%d\n",ans);
for(int i=0;i<=k;i++)
{
if(dp[k][i])
printf("%d ",i);
}
printf("\n");
return 0;
}