链接
分析:
挺难的构造,首先需要想到模数没有任何用,因为我们总能找到
k
k
k 个方案的答案,然后需要想到对于总体积
w
w
w,可以用若干个体积为
1
1
1 的小物品和 一个体积为
m
m
m 的大物品组成,其中这个
m
⩾
⌊
w
2
⌋
m \geqslant \left \lfloor \frac{w}{2} \right \rfloor
m⩾⌊2w⌋
这样子,每个方案只能选择一个大物品,设一共有
n
n
n 个体积为
1
1
1 的小物品,则大物品对于方案数的贡献为
C
n
w
−
m
C_n^{w-m}
Cnw−m,设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示一共有
i
i
i 个体积为
1
1
1 的小物品,组成方案数为
j
j
j 需要的大物品的数量,dp记录一下路径就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
int C[25][25],dp[25][20005],path[25][20005];
void init_C(){
for(int i=0;i<=20;i++) C[i][0]=1;
for(int i=0;i<=20;i++)
for(int j=1;j<=i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
void init_DP(){
memset(dp,63,sizeof(dp));
for(int i=0;i<=20;i++)
{
dp[i][0]=0;
for(int j=0;j<=20000;j++)
for(int k=0;k<=i;k++)
if(j+C[i][k]<=20000 && dp[i][j+C[i][k]]>dp[i][j]+1){
dp[i][j+C[i][k]]=dp[i][j]+1;
path[i][j+C[i][k]]=k;
}
}
}
int main(){
init_C();
init_DP();
int T;
scanf("%d",&T);
while(T--){
int w,P,k;
scanf("%d%d%d",&w,&P,&k);
for (int i=1;i<=20;i++)
if(dp[i][k]+i<=40){
printf("%d\n",dp[i][k]+i);
for (int j=1;j<=i;j++) printf("1 ");
while(k){
int m=path[i][k];
k-=C[i][m];
printf("%d ",w-m);
}
printf("\n");
break;
}
}
}