由于全是正整数,那么b[0]=1,那么b[1]的个数一定是1的个数,然后又因为这些1能组成其他数字,所以用b[1]个1进行01背包,得到其他数字,用f[i]表示能组成i的方法是多少,从1到m枚举,每次b[i]-f[i],若还剩余数字,那么一定是这个数组中的数。
因为n只有50,所以每次01背包直接从m到1跟新,50*1e4*70的复杂度还行,不要用sbmap存已经生成的数再去更新,反而超时没有for整个数组快。
#include<cstdio>
#include<cstring>
#include<map>
#define maxl 10010
using namespace std;
int n,m,cnt,cnt2,cas;
int a[maxl],ans[maxl];
long long b[maxl],f[maxl];
int num[maxl],numcnt[maxl];
int mul[maxl];
map <int,long long> mulsum;
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=m;i++)
scanf("%lld",&b[i]);
}
inline void mainwork()
{
memset(f,0,sizeof(f));
f[0]=1;cnt=0;
for(int i=1;i<=m;i++)
{
b[i]-=f[i];
if(b[i]>0)
{
num[++cnt]=i;
numcnt[cnt]=b[i];
for(int j=1;j<=b[i];j++)
for(int ii=m;ii>=i;ii--)
f[ii]+=f[ii-i];
}
}
}
inline void print()
{
cas++; cnt2=0;
for(int i=1;i<=cnt;i++)
for(int j=1;j<=numcnt[i];j++)
ans[++cnt2]=num[i];
for(int i=1;i<cnt2;i++)
printf("%d ",ans[i]);
printf("%d",ans[cnt2]);
printf("\n");
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}