Problem:
Coin Changing Problem
Find the minimum number of coins to make change for
n
cents using coins of denominations
d
1
,
d
2
,..,
d
m
. The coins can be used any number of times.
Input
n
m
d
1
d
2
...
d
m
Two integers
n
and
m
are given in the first line. The available denominations are given in the second line.
Output
Print the minimum number of coins in a line.
Constraints
1 ≤
n
≤ 50000
1 ≤
m
≤ 20
1 ≤ denomination ≤ 10000
The denominations are all different and contain 1.
Sample Input 1
55 4
1 5 10 50
Sample Output 1
2
Sample Input 2
15 6
1 2 7 8 12 50
Sample Output 2
2
Sample Input 3
65 6
1 2 7 8 12 50
Sample Output 3
3

Submitted solutions:

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <cmath>
#include<sstream>
#include<list>
#include<iomanip>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <bitset>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
#include <random>
#include <chrono>
using namespace std;
const long long LINF = 3e18 + 7;
const int MAX_N = 5000010;
const int MAX_W = 10002;
const int MAX_ARRAYK = 100000;
double PI = 3.14159265358979323846;
const int INF = 2147483647;
//using ll = long long;

int N, M;
int c[25];

bool has_bit(int n, int i) {
	return (n & (1 << i)) > 0;
}

int main() {

	cin >> N >> M;
	for (int i = 0; i < M; i++) {
		cin >> c[i];
	}

	int ALL = (1 << M);

	int ans = N;
	for (int n = 0; n < ALL; n++) {
		
		vector<int> v;
		for (int i = 0; i < M; i++) {
			if (has_bit(n, i)) {
				v.push_back(c[i]);
			}
		}

		sort(v.begin(), v.end(), greater<int>());

		int cnt = 0;
		int val = N;
		for (int i = 0; i < v.size(); i++) {
			cnt += (val / v[i]);
			val %= v[i];
		}

		if (val == 0) {
			ans = min(ans, cnt);
		}

	}
	cout << ans << endl;
	

	return 0;
}
accuracy: 0.4
time_ms: 210
memory_kb: 3424
final_rank: 8

code_snippet: #include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
using namespace std;

const int INF = (1<<29);

void dp(int v, vector<int> &memo, const vector<int> &value) {
    if (memo[v] == INF) {
        for (int i = 0; i < v; ++i) {
            memo[v] = min(memo[v], memo[i]+memo[v-i]);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    //値段をidxとして持つメモを使うDP

    int N, M;
    cin >> N >> M;
    vector<int> memo(N+1, INF);
    vector<int> value(M);
    for (int i = 0; i < M; ++i) {
        cin >> value[i];
    }

    //初期埋め
    for (auto v : value) {
        memo[v] = 1;
    }

    //bottom_up!
    for (int i = 0; i <= N; ++i) {
        dp(i, memo, value);
    }
    cout << memo[N] << endl;
    return 0;
}
accuracy: 1
time_ms: 560
memory_kb: 3460
final_rank: 2

code_snippet: #include <iostream>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <tuple>
#include <set>
#include <map>
#include <bitset>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cassert>
#include <unordered_set>
#include <unordered_map>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define all(v) v.begin(), v.end()

ll llpow(ll a, ll t)
{
  ll res = 1;
  rep(i, t) res *= a;
  return res;
}

ll inf = std::numeric_limits<ll>::max();

int main()
{
  ll n, m;
  cin >> n >> m;
  vector<ll> vec(m);
  rep(i, m)
  {
    cin >> vec[i];
  }
  sort(all(vec));
  vector<vector<ll>> dp(m, vector<ll>(n + 1, 10e6));
  rep(i, m)
  {
    rep(j, n + 1)
    {
      if (!j)
      {
        dp[i][j] = 0;
        continue;
      }
      if (!i)
      {
        if (!(j % vec[i]))
        {
          dp[i][j] = j / vec[i];
        }
        continue;
      }
      dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - vec[i] * (j / vec[i])] + (j / vec[i]), dp[i - 1][j - vec[i] * min(j / vec[i], (ll)1)] + min(j / vec[i], (ll)1)));
    }
  }
  // rep(i, m)
  // {
  //   rep(j, n + 1)
  //   {
  //     if (j)
  //     {
  //       cout << " ";
  //     }
  //     cout << dp[i][j];
  //   }
  //   cout << endl;
  // }
  cout << dp[m - 1][n] << endl;
}
accuracy: 0.4
time_ms: 10
memory_kb: 11228
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
typedef pair<int,int> PII;
const int INF=2e18;
void solve(){
	int n,m;cin>>n>>m;
	vector<PII>nums;
	for(int i=0;i<m;i++){
	 	int x;cin>>x;
	 	int c=1;
	 	while(x<=n){
	 	 	nums.push_back({x,c});
	 	 	x<<=1;
	 	 	c<<=1;
	 	}
	}
	m=nums.size();
	int dp[2][n+1];
	int now=0,pre=1;
	for(int i=0;i<=n;i++) dp[now][i]=INF;
	dp[now][0]=0;
	for(int i=0;i<m;i++){
	 	swap(now,pre);
	 	int x=nums[i].first,c=nums[i].second;
	 	for(int j=0;j<=n;j++){
			dp[now][j]=dp[pre][j];
			if(j-x>=0) dp[now][j]=min(dp[now][j],dp[now][j-x]+c);	 	 	
	 	}
	}
	int ans=dp[now][n];
	cout<<ans<<endl;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	solve();
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4244
final_rank: 1

code_snippet: //written by: tettyあ

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <cstring>
#include <utility>
#include <set>
#include <numeric>
#include <unordered_set>
#include <unordered_map>
#include <queue>

#include <iomanip>
#include <bitset>
#include <math.h>
#include <list>
#include <limits.h>
#include <stack>
#include <deque>
#include <functional> // std::greater

#include <random>
using namespace std;


typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef long long llong;
typedef unsigned long long ullong;

#define int llong

struct HashPair {

    static size_t m_hash_pair_random;

    template<class T1, class T2>
    size_t operator()(const pair<T1, T2>& p) const {

        auto hash1 = hash<T1>{}(p.first);
        auto hash2 = hash<T2>{}(p.second);

        size_t seed = 0;
        seed ^= hash1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= hash2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= m_hash_pair_random + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        return seed;
    }
};

size_t HashPair::m_hash_pair_random = (size_t)random_device()();


template<class T>istream& operator>>(istream& is, vector<T>& vec) { for (T& e : vec)is >> e; return is; }

struct OmomiEdge { int to, cost; };
struct FromToEdge { int from, to; };
struct OmomiFromToEdge {
    int from, to, cost;
    bool operator<(const OmomiFromToEdge& e) {
        return cost < e.cost;
    }
};

struct point { int x, y; };
using OmomiGraph = vector<vector<OmomiEdge>>;
using OmomiFromToGraph = vector<OmomiFromToEdge>;

// 辺の情報
struct Edge
{
    // 行先
    int to;

    // コスト
    int cost;
};

using Graph = std::vector<std::vector<Edge>>;

#define vecALL(vveecc) (vveecc).begin() , (vveecc).end() 
#define vecSORT(vveecc) sort((vveecc).begin(),(vveecc).end())
#define vecrSORT(vveecc) sort((vveecc).rbegin(),(vveecc).rend())


uint64_t uint64_floor_sqrt(uint64_t n) {
    if (n == 0) return 0;
    uint64_t tmp_m1 = std::sqrt(n) - 1;
    return tmp_m1 * (tmp_m1 + 2) < n ? tmp_m1 + 1 : tmp_m1;
}

// 1 以上 N 以下の整数が素数かどうかを返す
void Eratosthenes(int N,vector<int>&primes) {
    // テーブル
    vector<bool> isprime(N + 1, true);
    
    // 0, 1 は予めふるい落としておく
    isprime[0] = isprime[1] = false;

    // ふるい
    for (int p = 2; p <= N; ++p) {
        // すでに合成数であるものはスキップする
        if (!isprime[p]) continue;

        // p 以外の p の倍数から素数ラベルを剥奪
        for (int q = p * 2; q <= N; q += p) {
            isprime[q] = false;
        }
    }
    for (int i = 0; i <= N; i++) {

        if (isprime[i]) {
            primes.emplace_back(i);
        }
    }
    // 1 以上 N 以下の整数が素数かどうか
   // return isprime;
}
signed main() {
	int N, M; cin>> N >> M;
    vector<int>c(M); cin >> c;

    //dp[n][m] := m種類のコインを使用し、n円を支払う時のコインの最小枚数
	vector<vector<int>>dp(N + 10005, vector<int>(M + 1+5, 9999999));

    for(int m = 0; m <= M; m++) {
        dp[0][m] = 0; 
	}
    for(int m=1;m <= M; m++) {
        for (int n = 0; n <= N; n++) {
            if (n - c[m - 1] < 0) {
                dp[n][m] = dp[n][m - 1]; // コインを使わない場合
				continue;
            }
            dp[n][m] = min(dp[n][m - 1], dp[n - c[m - 1]][m] + 1);
        }
	}

    cout << dp[N][M] << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 17636
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>

template<class T> void chmin(T& a, T b) {
    if (a > b)
        a = b;
}

const int INF = 1000000000;

int main()
{
    int N, M;
    std::cin >> N >> M;
    std::vector<int> C(M), D(M);
    for (int i = 0; i < M; i++)
        std::cin >> C[i];
    std::sort(C.rbegin(), C.rend());
    for (int i = 0; i < M; i++)
        if (i == 0)
            D[i] = N / C[i];
        else
            D[i] = C[0] / C[i] + 1;

    std::vector<std::vector<int>> dp(M + 1, std::vector<int>(N + 1, INF));

    for (int i = 1; i <= M; i++) {
        for (int j = 0; j <= N; j++) {
            if (j > 0 && j % C[i - 1] == 0)
                chmin(dp[i][j], j / C[i - 1]);
            chmin(dp[i][j], dp[i - 1][j]);
            if (i > 1)
                for (int k = 1; k <= D[i - 1] + 1; k++) {
                    if (j - k * C[i - 1] > 0)
                        chmin(dp[i][j], dp[i - 1][j - k * C[i - 1]] + k);
            }
        }
    }

    std::cout << dp[M][N] << std::endl;

    return 0;
}
accuracy: 1
time_ms: 510
memory_kb: 7368
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
#define F first
#define S second
#define PII pair<int,int>
long long memo[30][50010];
    long long solve(int i,int amount,vector<int>&coins)
    {
        if (amount==0){return 0;}
        if(i==coins.size()||amount<0){return INT_MAX;}
        long long &ret=memo[i][amount];
        if(~ret){return ret;}
        return ret=min(solve(i,amount-coins[i],coins)+1,solve(i+1,amount,coins));
    }
int main() {

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    vector<int>coins;
    int amount,n;
    cin>>amount>>n;
    for (int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        coins.push_back(x);
    }
    memset(memo,-1,sizeof(memo));

    cout<<solve(0,amount,coins)<<endl;


    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 18216
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;


int main(){
  int n, m;
  cin>>n>>m;
  vector<int> k(m);
  for(int i = 0; i < m; i++) cin>>k[i];
  sort(k.rbegin(), k.rend());
  int ans = 1e9;
  for(int i = 0; i < (1 << m); i++){
    int temp = n;
    int cnt = 0;
    for(int j = 0; j < m; j++){
      if(i & (1 << j)){
        int t = temp / k[j];
        cnt += t;
        temp -= (t * k[j]);
      }
    }
    if(temp == 0){
      ans = min(ans, cnt);
    }
  }
  cout << ans << endl;
  return 0;
}
accuracy: 0.4
time_ms: 60
memory_kb: 3368
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

int main(){
    int n,m;
    cin >> n >> m;
    int MAX_COINS = m + 10;

    vector<int> coins(m+1);//dpテーブルを作る際、0indexの時の処理がめんどうなので

    for(int i = 1; i <= m; i++){
        cin >> coins[i];
    }

    vector<vector<int>> dp(m + 1, vector<int>(n + 1, MAX_COINS));
    //dp[][0]の時は0枚で作れることが確定
    for(int t=0; t<= m; t++){
        dp[t][0] = 0;
    }

    //dp[0][]の時はあり得ないのでMAX_COINSで埋めておく
    for(int x=1; x<=n; x++){
        dp[0][x] = MAX_COINS;
    }

    for(int t = 1; t <=m; t++){
        for(int x = 1; x <= n; x++){
            int v =  dp[t - 1][x];
            for(int u = 1; u <= x / coins[t]; u++){
                int tmp = dp[t-1][x -u*coins[t]] + u;
                v = min(v, tmp);
            }
            dp[t][x] = v;
        }
    }
    cout << dp[m][n] << endl;
}

//正しい解き方の方針
//次元を減らす→時間軸を無くすor
//時間軸を無くすとは？→一発の計算でどのコインを採用するのかを考える。すべてのインデックスを考慮してその1枚を加えるか加えないのかで考える
//どのインデックスかは関係なく、どれか壱枚を採用した際、というのを再帰で考える
//


/*
// Value関数の次元が大きすぎてTLEになる例

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n, m;
    cin >> n >> m;
    vector<int> coins(m+1);
    for(int i = 1; i <= m; i++) cin >> coins[i];
    // dpテーブルは小さい値からボトムアップに構築していくので，コインの額面を小さい順にしておく
    // コインの順番は３重ループの一番内側なのでこのソートは不要
    // sort(coins.begin(), coins.end());

    int MAX_COIN_NUMS = n + 100;
    vector<vector<int>> dp(m+1, vector<int>(n+1, MAX_COIN_NUMS));

    for(int t = 0; t <= m; t++) dp[t][0] = 0;
    for(int t = 1; t <= m; t++) {
        for(int sum = 1; sum <= n; sum++) {
            int res = dp[t-1][sum];
            for(int z = 1; z <= sum / coins[t]; z++)
                res = min(res, dp[t-1][sum - coins[t]*z] + z);
            dp[t][sum] = res;
        }
    }   

    cout << dp[m][n] << endl;
    return 0;
}
*/
accuracy: 0.6
time_ms: 850
memory_kb: 7116
final_rank: 6