[POJ 3181]Dollar Dayz[DP][高精度]

题目链接: [POJ 3181]Dollar Dayz[DP]

题意分析:

给出无穷多个1~K的价值的货币,问:能有多少种方式组合成N。

解题思路:

完全背包。dp[i] = dp[i] + dp[i - j]。j为货币价值。第i个价值可以有第i - j的价值加上价值为j的货币组成。

由于数量很大,需要高精度。这里我们可以使用ldp和hdp分别代表数字的低位和高位,整个数字长度就可以表示到1e36了,这里我们设低位上限为1e18。

记得输出结果的时候补上低位前导零!!!

个人感受:

想着楼梯那种dp,结果发现这题的组合数用楼梯的话会出现重复,例如1 2 2 1和 2 1 1 2是一样的,按楼梯那种写法会重复。结果完全背包从小到大放,完全不会出现重复的情况,我服。然后是像汇编一样使用数组,感觉棒棒哒。以后高精度就不用那么愁了,2333。

具体代码如下:

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define ll long long
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 1e3 + 111;
const ll up = 1e18;

ll hdp[MAXN], ldp[MAXN];

int main()
{
    int n, k; cin >> n >> k;
    for (int i = 1; i <= k; ++i) {
        ldp[0] = 1;
        for (int j = i; j <= n; ++j) {
            ldp[j] += ldp[j - i];
            hdp[j] += hdp[j - i];
            if (ldp[j] >= up) {
                ldp[j] -= up;
                ++hdp[j];
            }
        }
    }
    if (hdp[n]) {
        cout << hdp[n];
        ll x = ldp[n];
        int cnt = 0;
        while (x) {
            ++cnt;
            x /= 10;
        }
        for (int i = 0; i < 18 - cnt; ++i) {
            cout << 0;
        }
        cout << ldp[n] << '\n';
    }
    else
        cout << ldp[n] << '\n';
    return 0;
}



你可能感兴趣的:(dp,高精度)