POJ_3181 Dollar Dayz
dp, bit int

Thoughts

Here the problem is POJ.

The number of ways to buy total $N by the combination of $1~$K.
The first thought is if I can compose $5, I can also compose $5+1 or $5+2 til $5+K. However, the problem needs to know how many ways. So, I try to draw a form NxK and fill it to know what I will think when I do so. And, I am lazy, so I prefer to find the general rules to fill.
It’s the part I like DP (also Greedy) and I won’t draw it again(?).

題目所求為用$1~$K組出$N有幾種組合。
第一個想法是,當我能夠組出$5時,我同時可以組出$5+1或$5+2..或$5+K。
但題目問的是有幾種。
因此試著畫NxK的表格,並將它填滿。 在填表格的時候我會去記我的想法,或者說,找出該格的最佳解可以(最好)由哪些組成。 最好能夠找出共通點。
這部分是我喜歡DP原因,所以我不會畫出來的(?)。

Anyway, I find that if I want to $i to compose $j, it’s the best to take the number of ways of $j(that I want to compose)-$i in each $1~i.
That is, if I use $1 to compose $2, the number of ways is 1.
Use $2 to compose $2, the number will be 2.
Then use $3 to compose $5, there are two ways to compose.

One is (1, 1, 2). The other is (2, 3).

So try to use adding the number of ways of $1 to compose $2 and $2 to compose $2.

總之,每一格都有著一個共通點是,當我要用$i組出$j時,最好的辦法是拿從$1~$i裡組出$j-i的數。
用$1組$2,方法是1。
用$2組$2,方法是1。
當用$3組$5時,方法會是2。

(1, 1, 3)或者是(2, 3)。

這會造成每次都要刷過一次$1~i。
那麼就試著將他們加起來呢?

It’s totally fine.

這是可以的。 (可以可以。可以可以。放心可以。)

DP

  dp[i][j] = dp[i][j - i] + dp[i - 1][j];
    
  dp[i][j] is the number of ways to compose $j by using $1~i.
    
  dp[i][j]是用$1~i組出$j方法數的最佳解。

Addition

However, I got WA.
And the reason is the answer is more than 64 bits.

只是我吃WA了。
原因是因為這題答案會大於64 bits。ˊ_>ˋ

不知道有沒有人能夠告訴我怎麼在想得時候就發現呢

Code

#include <iostream>
#include <cstring>
#include <string>
using namespace std;
char dp[105][1005][50];
void ADD(int Xi, int Xj, int Yi, int Yj){ //big int addition, 大數加法
    int i, j, l = strlen(dp[Xi][Xj]), L = strlen(dp[Yi][Yj]);
    char a, b;
        for(i = j = 0; i < l || i < L; i++){
              a = dp[Xi][Xj][i]; b = dp[Yi][Yj][i];
              if(i >= l) a = '0';
              else if(i >= L) b = '0';
              j += (int)(a - '0' + b - '0');
              dp[Xi][Xj][i] = (char)(j % 10 + '0');
              j /= 10;
        }
    if(j) dp[Xi][Xj][i] = (char)(j % 10 + '0');
}
int main(void){
    int N, K, i, j;
    scanf("%d %d", &N, &K);
  
    for(i = 1, dp[0][0][0] = '1'; i <= K; i++){ //DP
        for(j = 0; j <= N; j++){
        if(j - i >= 0) ADD(i, j, i, j - i);
        ADD(i, j, i - 1, j);
        }
    }
  
    for(i = strlen(dp[K][N]) - 1; i >= 0; i--) printf("%c", dp[K][N][i]);
    printf("\n");
}

寫完題解的心得就是好花時間,希望如果有對這題完全沒想法的人能夠一段一段邊看邊try try看。
*****
Written by Mi on 01 December 2016