2013-03-16 15:40:05Morris

[ZJ][DP] a646. 小民買糖果


內容 :

某天某糖果店舉辦活動:集滿 n 張糖果包裝紙即可再多得一顆糖果。而 n 卻是由顧客由抽獎決定,這樣無良的老闆所設計出來的活動實在是讓店員很困擾,不知道該給客人幾顆糖果。希望你們寫個程式幫店員小姐解決這個問題。

 

原題如上描述


額外補充

然而這已經換成匯率問題,小民每次拿 n 張去兌換時,只能兌換 n * p (無條件捨去取整數) 個糖果,而此時換到的糖果也有包裝紙,又可以再次兌換,問一開始給小民 c 個糖果,根據匯率 p,小民最多能換到幾顆糖果。

輸入說明 :

正整數 c 代表顧客買幾顆糖果。

浮點數 p 介於 0 ~ 1,代表一張包裝紙可以換幾顆糖果。

 

0 < c < 1000, p 至多小數點三位

輸出說明 :

顧客最多能獲得幾顆糖果。

範例輸入 :

15 0.2
15 0.3

範例輸出 :

18
20

提示 :

出處 :

中央助教 (管理:morris1028)



方程:dp[n] = max(dp[n + floor(i*p) - i] + floor(i*p)), 0<i<=n,
狀態:dp[n] 表示 n 張包裝紙的最大糖果數,i 是拿多少去兌換。
因此最後輸出 dp[c]+c

不可以使用 double 型態去處理,會有誤差

/****************************************************************/
/*  Problem: a646 "小民買糖果" from 中央助教                       */
/*  Language: CPP (1024 Bytes)                                  */
/*  Result: AC(224ms, 268KB) judge by this@ZeroJudge            */
/*  Author: morris1028 at 2013-03-15 19:59:44                   */
/****************************************************************/


#include <stdio.h>
#include <string.h>
int dp[1000], a, b;
int shift[1000], shift_v[1000];
char used[1000];
int build(int n) {
    if(n == 0)
        return 0;
    if(used[n])
        return dp[n];
    int i, v, tmp;
    dp[n] = 0;
    for(i = shift[n]; i >= 1; i = shift[i-1]) {
        v = shift_v[i];
        tmp = build(v+n-i) + v;
        if(tmp > dp[n])
            dp[n] = tmp;
    }
    used[n] = 1;
    return dp[n];
}
int main() {
    int n, i, j, k;
    char s[50];
    while(scanf("%d %s", &n, &s) == 2) {
        for(i = 2, a = 0, b = 1; s[i]; i++)
            b *= 10, a = a*10 + s[i]-'0';
        for(i = 1; i <= n; i++)
            shift_v[i] = i*a/b;
        for(i = n, k = n; i >= 0; i--) {
            if(i == 0 || shift_v[i] != shift_v[i-1]) {
                for(j = i; j <= k; j++)
                    shift[j] = i;
                k = i-1;
            }
        }
        memset(used, 0, sizeof(used));
        printf("%d\n", build(n)+n);
    }
    return 0;
}