题意:有N种硬币,每种硬币的价值是Ai、数量是Ci,问题是用这些硬币能表示多少m以内的价值。
思路:背包问题,正常做是铁定会超时的,可以考虑用01背包+2进制优化。这样的话交上去437多ms,其实还有可以优化的地方,考虑到若Ai*Ci>=m,则可以看成硬币的数量是无限的,这种情况就可以看成是多重背包,优化以后时间可以降低到171ms。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
const int maxn=100000+10;
int dp[maxn],v[maxn],w[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int m,n;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
for(int i=1;i<=n;++i)
scanf("%d",&v[i]);
for(int i=1;i<=n;++i)
scanf("%d",&w[i]);
memset(dp,0,sizeof(dp));
dp[0]=true;
for(int i=1;i<=n;++i)
{
if(v[i]*w[i]>=m)
{
for(int u=v[i];u<=m;++u)
{
dp[u]=dp[u-v[i]]|dp[u];
}
continue;
}
int k=1;
int p=0;
while(p<w[i])
{
for(int j=m;j>=k*v[i];--j)
{
dp[j]=dp[j-k*v[i]]|dp[j];
}
p+=k;
k*=2;
if(k+p>w[i]&&p<w[i])
{
k=w[i]-p;
}
}
}
int ans=0;
for(int i=1;i<=m;++i)
if(dp[i]) ans++;
printf("%d\n",ans);
}
return 0;
}