D - Money in Hand Editorial by en_translator
This problem can be solved with a DP (Dynamic Programming).
We define a two-dimensional array \(dp[i][j]\) \((0\leq i\leq N, 0\leq j\leq X)\) to be “True
if it is possible to pay exactly \(j\) yen with \(B_1\) coins worth \(A_i\) yen, \(B_2\) coins worth \(A_2\) yen, \(\ldots\), and \(B_i\) coins worth \(A_i\) yen; and False
otherwise.” We consider determining for \(i=0,1,\ldots,N\) in this order.
The answer to the problem is Yes
if \(dp[N][X]\) is True
, and No
if it is False
.
First, for \(i=0\), Takahashi has no coins, so \(dp[0][0]=\)True
and \(dp[0][j]=\) False
for \(j>0\).
Now suppose that we know \(dp[i-1][j]\) \((0\leq j\leq X)\). How can we find \(dp[i][j]\)?
We can use between \(0\) and \(B_i\) coins worth \(A_i\) yen,
so \(dp[i][j]\) is True
if there is at least one integer \(k\) satisfying \(0\leq k\leq B_i\) such that \(j-kA_i\geq 0\) and \(dp[i-1][j-kA_i]=\), and False
otherwise.
Formally,
\[ dp[i][j]=dp[i-1][j]\lor dp[i-1][j-A_i]\lor dp[i-1][j-2A_i]\lor \cdots\lor dp[i-1][j-B_iA_i]\quad (\text{where }dp[i-1][j']=\text{False}\text{ if }j'<0). \]
A naive implementation of this DP costs \(O(B_iX)\) for each \(i\), for a total of \(O((\displaystyle\sum_{i=1}^N B_i)X)\), which is fast enough under the Constraints of this problem. Therefore, the problem has been solved.
About \(O(NX)\) solution
This problem can also be solved in an \(O(NX)\) time.
The fundamental idea is same as before, but when finding \(dp[i][j]\),
we compute \(dp'[i-1][j]=\) ( the maximum \(j'\) among \(j'=j,j-A_i,j-2A_i,\ldots\) such that \(dp[i-1][j']=\)True
) (or \(-\infty\) if there is no such \(j'\)),
for each \(j\).
Each \(dp'[i-1][j]\) can be filled in ascending order of \(j\), \(dp'[i-1][j]=j\) if \(dp[i-1][j]=\)True
and \(dp'[i-1][j]=dp'[i-1][j-A_i]\), in an \(O(1)\) time each.
What is more, by the recurrence relation that we derived in the solution above, \(dp[i][j]\) turns out to be True
if \(dp'[i-1][j]\geq j-A_iB_i\) and False
otherwise,
which can be evaluated in an \(O(1)\) time as well.
Thus, the DP table is filled in an \(O(X)\) time for each \(i\), for a total of \(O(NX)\) time.
Sample code in C++ (base solution):
#include <bits/stdc++.h>
using namespace std;
int main(void){
int n,x;
int a[50];
int b[50];
bool dp[51][10001];
cin>>n>>x;
for(int i=0;i<n;i++)cin>>a[i]>>b[i];
for(int i=0;i<=n;i++)for(int j=0;j<=x;j++)dp[i][j]=false;
dp[0][0]=true;
for(int i=0;i<n;i++){
for(int j=0;j<=x;j++){
for(int k=0;k<=b[i];k++){
if(j>=a[i]*k){
if(dp[i][j-a[i]*k])dp[i+1][j]=true;
}
}
}
}
if(dp[n][x])cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
Sample code in C++ (\(O(NX)\) solution):
#include <bits/stdc++.h>
using namespace std;
int main(void){
int n,x;
int a[50];
int b[50];
bool dp[10001]; //we reuse the array
int mx[100];
cin>>n>>x;
for(int i=0;i<n;i++)cin>>a[i]>>b[i];
for(int i=0;i<=x;i++)dp[i]=false;
dp[0]=true;
for(int i=0;i<n;i++){
for(int j=0;j<a[i];j++)mx[j]=-10000; //-a[i]*b[i]未満なら良い
for(int j=0;j<=x;j++){
if(dp[j])mx[j%a[i]]=j;
if(mx[j%a[i]]>=j-(a[i]*b[i]))dp[j]=true;
else dp[j]=false;
}
}
if(dp[x])cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
posted:
last update: