けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AOJ 1167 ポロック予想 (ICPC 国内予選 2010 C) (250 点)

いわゆる、重複ありのナップサック問題

問題へのリンク

問題概要

整数  N を最小個数の四面体数 (重複あり) の和として表せ。

解法

四面体数は、mC3 の形で表される。
重複ありのナップサックも、うまくやれば、種類数の線形オーダーで効率的に解けることの練習。

#include <iostream>
#include <vector>
using namespace std;

const int MAX = 1000100;
const int INF = 1<<29;

int main() {
    vector<int> dp(MAX, INF), odddp(MAX, INF);
    dp[0] = odddp[0] = 0;
    for (int i = 1;; ++i) {
        int num = i * (i+1) * (i+2) / 6;
        if (num >= MAX) break;
        for (int j = num; j < MAX; ++j) {
            dp[j] = min(dp[j], dp[j-num]+1);
            if (num & 1) odddp[j] = min(odddp[j], odddp[j-num]+1);
        }
    }
    int n;
    while (cin >> n) {
        if (n == 0) break;
        cout << dp[n] << " " << odddp[n] << endl;
    }
}