题目描述】
云云最近迷上了赛车,自己买来了N种赛道来搭建一个长为L的赛道。云云列了一个清单,表明了每种赛道的个数ni,该种赛道的长度li,想请你帮忙计算有多少种搭建一个长为L的赛道的方案。
【输入格式】
第一行,两个数,分别为N、L。
接下来的N行,第i+1行为一组赛道数据ni、li。
【输出格式】
一行,一个数,搭建一个长为L的赛道的方案总数。由于数字可能很大,请输出方案总数取10007的模后的值。
【样例】
INPUT | OUTPUT |
2 6 3 2 2 3 | 2 |
【数据范围】
对于10%的数据,0<N,L≤10。
对于50%的数据,0<N,L≤1000。
对于100%的数据,0<N,L≤5000,0<ni≤1000,0< li≤L。
【Hint】
不同的方案指使用不同种的赛道、使用不同数量的赛道。
事实上,本题不用判断方案是否相同。
题意分析:是一个多重背包问题吧!但是这个题目求的是方案的总数,与多重背包原型又有所不同。
AC代码:
#include <cstdio>
#include<cstring>
#define MAXN 5005
using namespace std;
int q[MAXN],w[MAXN],dp[MAXN],N,L;
void CPack(int len){ //完全背包处理。
for(int i=len;i<=L;++i)
dp[i]=(dp[i]+dp[i-len])%10007; //长度为i的路径总数由原有条数加上长度(i-len)的条数。
}
void ZOPack(int len){ //按0-1背包处理
for(int i=L;i>=len;--i)
dp[i]=(dp[i]+dp[i-len])%10007; //长度为i的路径总数由原有条数加上长度(i-len)的条数。
}
void MPack(int k){
if(q[k]*w[k]>=L){
CPack(w[k]);
return;
}
for(int i=1;i<q[k];q[k]-=i,i<<=1)
ZOPack(w[k]*i);
ZOPack(w[k]*q[k]);
}
int main(){
while(~scanf("%d%d",&N,&L)){
for(int i=0;i<N;++i)
scanf("%d%d",&q[i],&w[i]);
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=0;i<N;++i)
MPack(i);
printf("%d\n",dp[L]);
}
return 0;
}
路途中。。。。