题目链接:http://poj.org/problem?id=1742
Time Limit: 3000MS | Memory Limit: 30000K | |
Total Submissions: 33242 | Accepted: 11283 |
Description
Input
Output
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
题意;n种硬币,目标金钱是m。每种硬币给你数目和价值,问在1~m之前最多能组成多少种钱。
思路:楼教主“男人八题”之一,此题看似简单,数据却十分变态。错的基本都是TLE。 二进制多重背包过不了,单调队列优化的多重背包也过不了,加了混合背包单调队列才卡过,只能说自己太弱了。对单调队列的理解不够深。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define M 100010
#define N 110
int dp[M];
int b[M];
int l,r;
int n,m;
int s[N],flag[M];
int main()
{
int num,sum;
while(~scanf("%d %d",&n,&m)&&(n+m))
{
for(int i=1; i<=n; i++)
scanf("%d",&s[i]);
for(int i=1; i<=m; i++)
dp[i]=0;
dp[0]=1;
for(int i=1; i<=n; i++)
{
scanf("%d",&num);
int v=s[i];
if(num==1)
{
for(int j=m; j>=v; j--)
if(!dp[j]&&dp[j-v])
dp[j]=1;
}
else if(num*v>=m)
{
for(int j=v; j<=m; j++)
if(!dp[j]&&dp[j-v])
dp[j]=1;
}
else
{
for(int d=0; d<v; d++)
{
sum=0,l=1;r=0;
for(int j=d;j<=m;j+=v)
{
if(r-l+1>num)
sum-=b[l++];
b[++r]=dp[j];
sum+=dp[j];
if(!dp[j]&&sum)
dp[j]=1;
}
}
}
}
int t=0;
for(int i=1;i<=m;i++)
if(dp[i])
t++;
printf("%d\n",t);
}
return 0;
}