Description
经过一天辛苦的工作,小Q进入了梦乡。他脑海中浮现出了刚进大学时学01背包的情景,那时还是大一萌新的小Q解
决了一道简单的01背包问题。这个问题是这样的:给定n个物品,每个物品的体积分别为v_1,v_2,…,v_n,请计算
从中选择一些物品(也可以不选),使得总体积恰好为w的方案数。因为答案可能非常大,你只需要输出答案对P取
模的结果。因为长期熬夜刷题,他只看到样例输入中的w和P,以及样例输出是k,看不清到底有几个物品,也看不
清每个物品的体积是多少。直到梦醒,小Q也没有看清n和v,请写一个程序,帮助小Q一起回忆曾经的样例输入。
Input
第一行包含一个正整数T(1<=T<=100),表示测试数据的组数。
接下来T行,每行3个整数w,P,k(50<=w<=20000,1<=P<=2^30,0<=k<=min(20000,P-1))
分别表示每组需要回忆的测试数据的相关参数。
Output
对于每组数据,第一行输出n(1<=n<=40)。
第二行输出n个正整数v_1,v_2,…,v_n(1<=v_i<=20000),分别表示每个物品的体积。
若有多组可行解,输出任意一组。输入数据保证对于每组数据至少存在一组可行解。
Sample Input
4
50 1013 4
50 3 1
80 5 1
扫描二维码关注公众号,回复: 5073290 查看本文章100 1000000007 13
Sample Output
5
10 20 20 30 50
5
10 20 20 30 50
8
10 20 30 40 50 60 70 80
11
12 18 20 13 41 30 15 11 11 250 28
题解
非常吼的一道构造啊.
主要思路在于,我们要做到:两种物品分开来都不能贡献,只有合在一起的时候才能精准做出贡献
把物品分成两种:一种是大小为1的小物品,另一种是大小至少为 的大物品
显然只能将这两种物品组合在一起的时候才会有贡献
并且一定是一个大物品+一些小物品的组合
可以设一个 表示用了 个小物品,方案数为 的最少大物品数量
转移可以枚举这个大物品比 小了k,显然他的贡献就是
预处理一下就好了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=25;
const int MAXK=20005;
int C[MAXN][MAXN];
int f[MAXN][MAXK],pre[MAXN][MAXK];
void init()
{
C[0][0]=1;
for(int i=1;i<=20;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)C[i][j]=C[i-1][j]+C[i-1][j-1];
}
}
int main()
{
init();
memset(f,63,sizeof(f));int inf=f[0][0];
for(int i=0;i<=20;i++)
{
f[i][0]=0;
for(int j=0;j<=20000;j++)
for(int k=0;k<=i;k++)
if(j+C[i][k]<=20000&&f[i][j+C[i][k]]>f[i][j]+1)
{
f[i][j+C[i][k]]=f[i][j]+1;
pre[i][j+C[i][k]]=k;
}
}
int T=read();while(T--)
{
int w=read(),P=read(),ans=read();
if(!ans){puts("1\n1");continue;}
// bool tf=false;
for(int i=0;i<=20;i++)if(i+f[i][ans]<=40)
{
pr2(i+f[i][ans]);
for(int j=1;j<=i;j++)pr1(1);
int u1=ans;
for(int j=1;j<=f[i][ans];j++)
{
pr1(w-pre[i][u1]);
u1-=C[i][pre[i][u1]];
}
puts("");
break;
}
}
return 0;
}