云云搭赛道

题目链接:https://www.contesthunter.org/Contest/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98%E6%AC%A2%E4%B9%90%E8%B5%9B/Problem/Show/%E4%BA%91%E4%BA%91%E6%90%AD%E8%B5%9B%E9%81%93


题目描述】

云云最近迷上了赛车,自己买来了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;
}



路途中。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值