题目描述
银岛上的人使用银岛币。这些金币分别价值A1,A2,A3…An银岛币。一天托尼打开他的钱包,发现有一些银岛币。他决定在附近商店买一个非常好的表。他想给商店正好的钱(就是商店不用找零)并且他知道表的价格不会超过m银岛币。但他不知道表的精确价格。
你的任务是写一个读入A1,A2,A3…An和C1,C2,C3…Cn的程序。(C1,C2,C3…Cn表示托尼有A1,A2,A3…An的个数)判断1到m中有多少种价格托尼可以付。
输入
输入包括几组测试数据。每组测试数据的第一行包括2个整数n,m(1<=n<=100),m(m<=100000)。第二行包括2n个整数A1,A2,A3…An和C1,C2,C3…Cn,(1<=Ai<=100000,1<=Ci<=1000),测试数据末尾有2个0。
输出
输出每组测试数据的结果。一组一行。
分析
资料上说是单调队列写的多重背包,但是——
poj的[Discuss]有一种神奇的思路:
这不是多重背包,只是问可不可以达到这个状态罢了,不用最优值!!!
所以设f[i]表示可以不可以付i的钱。
每次从可以付的钱出发,往后推那些也是可以付的就可以了。(我表达不出来啊~~)
自行体会代码233
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
bool f[200000];
int num[200000];
int a[2000],b[2000];
int n,m;
int main()
{
while (1==1)
{
scanf("%d%d",&n,&m);
if (n==0&&m==0) return 0;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
scanf("%d",&b[i]);
int ans=0;
memset(f,0,sizeof(f));
f[0]=true;
for (int i=1;i<=n;i++)
{
memset(num,0,sizeof(num));
for (int j=a[i];j<=m;j++)
{
if (!f[j]&&f[j-a[i]]&&(num[j-a[i]]+1<=b[i]))
{
ans++;
f[j]=true;
num[j]=num[j-a[i]]+1;
}
}
}
printf("%d\n",ans);
}
}