观察到通过不同的数额,去组成1e5,那么n就是log级别的,大约再460以内
我们可以做两次dp,一次从前往后,f[i][j]表示前i种纸币能否组成金额j,第二次从后往前,g[i][j]表示后i种纸币能否组成金额j
之后对于每种纸币,我们需要考虑前缀也就是f,能否组成k,后缀能否组成m-k()
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int maxm=460;
int n,m,cnt,tt,st[maxn],ua[maxn],a[maxn],c[maxn],mp[maxn];
bitset <maxn> f[maxm],g[maxm];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
if(a[i]!=a[i-1]) ua[++cnt]=a[i];
c[cnt]++;//去重
}
f[0][0]=g[cnt+1][0]=1;
for(int i=1;i<=cnt;i++)
{
f[i]=f[i-1];
int x=c[i];
for(int j=1;j<=x;x-=j,j<<1)
f[i]|=f[i]<<(j*ua[i]);
f[i]|=f[i]<<(x*ua[i]);
}
for(int i=cnt;i>=1;i--)
{
g[i]=g[i+1];
int x=c[i];
for(int j=1;j<=x;x-=j,j<<1)
g[i]|=g[i]<<(j*ua[i]);
g[i]|=g[i]<<(x*ua[i]);
}
for(int i=1;i<=cnt;i++)
{
int flag=0;
for(int j=0;j<=m;j++)
if(f[i-1][j] && g[i+1][m-j])
{
flag=1;
break;
}
if(!flag) st[++tt]=ua[i];
}
printf("%d\n",tt);
for(int i=1;i<=tt;i++) printf("%d ",st[i]);
return 0;
}