POJ-3181 Dollar Dayz

Dollar Dayz

Time Limit: 1000MS
Memory Limit: 65536K

Description

Farmer John goes to Dollar Days at The Cow Store and discovers an unlimited number of tools on sale. During his first visit, the tools are selling variously for $1, $2, and $3. Farmer John has exactly $5 to spend. He can buy 5 tools at $1 each or 1 tool at $3 and an additional 1 tool at $2. Of course, there are other combinations for a total of 5 different ways FJ can spend all his money on tools.

Here they are:

  1. $1 + $1 + $1 + $1 + $1
  2. $1 + $1 + $1 + $2
  3. $1 + $2 + $2
  4. $1 + $1 + $3
  5. $2 + $3

Write a program than will compute the number of ways FJ can spend N dollars (1 <= N <= 1000) at The Cow Store for tools on sale with a cost of 1.. 1.. 1..K (1 <= K <= 100).

Input

A single line with two space-separated integers: N and K.

Output

A single line with a single integer that is the number of unique ways FJ can spend his money.

Sample Input

5 3

Sample Output

5

Reference Code

#include <cstdio>
#include <cstring>
typedef long long ll;
const int MAXN = 1e3 + 10;
struct llll{
    static const long long BASE = 1e18;
    long long first, second;
    llll (long long x=0):first(0),second(x){}
    llll operator+(const llll &oth)const{
        llll res;
        long long tmp = (second + oth.second) / BASE;
        res.second = (second + oth.second) % BASE;
        res.first = first + oth.first + tmp;
        return res;
    }
    bool operator+(){return (bool)(first||second);}
    friend void print(const llll &num){
        if (num.first)
            printf("%lld%018lld\n", num.first, num.second);
        else printf("%lld\n", num.second);
    }
};
llll dp[MAXN][MAXN];
llll solve(int n, int m){
    if (+dp[n][m]) return dp[n][m];
    if (!n || m == 1) return 1;
    if (n < m) return solve(n, n);
    return dp[n][m] = solve(n, m - 1) + solve(n - m, m);
}
int main(){
    int n, k;
    while (~scanf("%d%d", &n, &k)){
        print(solve(n, k));
    }
    return 0;
}

Tips

题意:
给你两个数 n n n k k k ,请你求解将 n n n 分解为若干个不大于 k k k 的数的方法数。
数据范围 1 ⩽ n ⩽ 1000 1\leqslant n \leqslant 1000 1n1000 1 ⩽ k ⩽ 100 1 \leqslant k \leqslant 100 1k100

解法:
设题中所求为函数 f ( n , k ) f(n,k) f(n,k) 。我们将满足这些要求的数分成两类,一类是含有 k k k 的,一类是不含 k k k 的。含 k k k 的共有 f ( n − k , k ) f(n-k,k) f(nk,k) 个,不含 k k k 的共 f ( n , k − 1 ) f(n,k-1) f(n,k1) 个。则有递推式 f ( n , k ) = f ( n − k , k ) + f ( n , k − 1 ) f(n,k)=f(n-k,k)+f(n,k-1) f(n,k)=f(nk,k)+f(n,k1)

由于本题的数据范围较大,因而需要考虑高精度。但本题的数据也不是那么大,可以使用两个long long型拼接成一个大数。(这是以前没有学过的技巧)

本题第一次提交的时候TLE了,因为直接使用了大数模板。
第二次提交WA了,找了Discuss里面的测试数据,发现有一条

465 89
29815691381598866122

和我的答案

298015691381598866122

有一个0的差别。
通过将代码中printf("%lld%018lld\n", num.first, num.second);一句改为printf("%lld%lld\n", num.first, num.second);即AC。然而这实际上并不是对的。

这个问题通过查阅别人已AC的代码也能看出,基本这些代码都不会打印前导零。

尽管本题可能确实有问题,但是用两个long long拼一个大整数的这样的技巧还是值得学习的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值