传送门
解析:
数据太弱了。。。听说连二进制拆分做0/10/10/1背包都能水过这道题。
思路:
我的做法复杂度是O(nm)O(nm)O(nm)。主要就是对于每一种硬币,我们将之前能够凑出来的钱数加上这个硬币做状态转移,记录一个sumsumsum数组,每次清空,sumjsum_{j}sumj表示凑出jjj的前需要用到的最少的当前硬币。
然后就可以直接状态转移搞一搞了。
代码:
#include<iostream>
#include<cstdio>
#include<cctype>
#include<stack>
#include<cstring>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=103,M=100005;
int n,m;
int a[N],c[N];
bool ok[M];
int sum[M];
stack<int> st;
signed main(){
while(n=getint(),m=getint(),n!=0||m!=0){
for(int re i=1;i<=n;++i)a[i]=getint();
for(int re i=1;i<=n;++i)c[i]=getint();
memset(ok,0,sizeof ok);ok[0]=true;
int ans=0;
for(int re i=1;i<=n;++i){
while(!st.empty())sum[st.top()]=0,st.pop();
for(int re j=a[i];j<=m;++j){
if(!ok[j]&&ok[j-a[i]]&&sum[j-a[i]]<c[i]){
ok[j]=true;
st.push(j);
sum[j]=sum[j-a[i]]+1;
++ans;
}
}
}
cout<<ans<<"\n";
}
return 0;
}