明显dp题,但是如何高效dp则是个问题;
令dp[i][j]表示用前i种硬币表示面值j时第i种硬币最多能剩多少个,那么,
1.如果dp[i-1][j]>=0,也就是前i-1种就能拼出j的话,那么dp[i][j]自然就是c[i]了;
2.如果j < a[i](第i种的面值)或者dp[i][j-a[i]]<=0(j比a[i]小或者用前i种根本就拼不出j-a[i]),则dp[i][j]=-1;
3.剩下的,dp[i][j]=dp[i][j-a[i]]-1;
同时注意到当前状况仅与上一次的状态有关,故可压缩i;
每次循环j从小到大,这样的话,就可以保证1中的dp[j]是上一次循环的值而2,3中的dp[j-a[i]]为本次循环后的值。
最后,注意j必须从0开始!!!
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int n, m, i, j, k;
int f[100005], a[105], c[105];
while (cin >> n >> m && n) {
for (i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (i = 1; i <= n; i++)
scanf("%d", &c[i]);
memset(f, -1, sizeof(f));
f[0] = 0;//初始化,f[0][0]=0;
for (i = 1; i <= n; i++)
for (j = 0; j <= m; j++) {//从0开始!!!
if (f[j] >= 0)//如果[i-1][j]>=0
f[j] = c[i];
else if (j < a[i] || f[j - a[i]] <= 0)//如果f[i][j-a[i]]<=0,注意这里的f[j-a[i]]代表的是本次循环的值!!!
f[j] = -1;
else {
f[j] = f[j - a[i]] - 1;
}
}
int cnt = 0;
for (i = 1; i <= m; i++)
if (f[i] >= 0)cnt++;
cout << cnt << endl;
}
return 0;
}