2013-01-24 09:51:07Morris

[ZJ][DP] d944. B. 卡卡跑丁車

內容 :

  「卡卡跑丁車」是一款最新型的賽車遊戲,由超可愛的角色、超酷炫的跑丁車陪你一起軋車甩尾,操作簡單容易上手,輕鬆休閒不麻煩!你只要在遊戲中,使用小技巧陷害對手,讓自己在時間內跑完全程,就可以獲得勝利唷!

  在遊戲中遇到彎道時,通常需要減速以求安全過彎,而跑丁車提供了另一個選擇一甩尾!!雖然甩尾會使過彎速度下降,但累積三次甩尾後便可換取一個加速器,可以大幅縮減通過直線的時間!!可惜的是,當你囤積了兩個未使用的加速器後,再次甩尾並不會被累積計算。

  卡卡是一名跑丁車玩家,由於缺乏經驗經常拿不到第一名。他最大的問題就是不清楚應該何時甩尾與使用加速器。他請你寫一個程式來提醒他在正確的地點做正確的事。

  神奇的是卡卡平常通過任何彎道都需要 5 單位時間,若甩尾過彎則需平常的兩倍,也就是 10 單位時間。對於直線賽道來說,每通過 1 單位長度需要 2 單位的時間,若使用加速器則所需時間減半。

  當然卡卡只會在彎道甩尾、直線使用加速器,並且一個彎道只能甩尾一次、一個加速器僅作用於一條直線賽道。

輸入說明 :

測資包含多組測試資料,第一列有一個整數 T 表示接下來有幾組測試資料。每組測試資料表示一場競賽的全程路線,其第一列有一個整數 N ,代表接下來有幾條直線賽道,相鄰兩個直線賽道間恰有一個彎道。下一列有 N 個非負整數,依序給出了每條直線賽道的長度。起點為第一條直線的首端,終點為最後一條直線的末端,賽道的總長度不會超過 231 − 1 (1 ≤ N ≤ 10000)

輸出說明 :

對每筆測試資料輸出卡卡到達終點所需的最短時間。

範例輸入 :

2
5
10 10 10 10 10
5
10 10 10 40 10

範例輸出 :

120
155

提示 :

出處 :

2010 NPSC 高中組初賽 (管理:pcshic)



/**********************************************************************************/
/*  Problem: d944 "B. 卡卡跑丁車" from 2010 NPSC 高中組初賽             */
/*  Language: CPP (1594 Bytes)                                                    */
/*  Result: AC(32ms, 964KB) judge by this@ZeroJudge                               */
/*  Author: morris1028 at 2013-01-24 09:32:04                                     */
/**********************************************************************************/


#include <stdio.h>
#include <algorithm>
using namespace std;
#define oo 1LL<<60
int main() {
    int t, n;
    long long x, dp[10000][3][3];
    /* [012],[012] 甩尾次數 氮氣*/
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        int i, j, k;
        for(i = 0; i < n; i++)
            for(j = 0; j < 3; j++)
                for(k = 0; k < 3; k++)
                    dp[i][j][k] = oo;
        scanf("%lld", &x);
        dp[0][0][0] = 2*x;
        for(i = 1; i < n; i++) {
            scanf("%lld", &x);
            for(j = 0; j < 3; j++) {
                for(k = 0; k < 3; k++) {
                    dp[i][j][k] = min(dp[i][j][k], dp[i-1][j][k]+5+2*x);
                    if(j-1 >= 0) //僅甩
                        dp[i][j][k] = min(dp[i][j][k], dp[i-1][j-1][k]+10+2*x);
                    if(k+1 < 2)  //僅噴
                        dp[i][j][k] = min(dp[i][j][k], dp[i-1][j][k+1]+5+x);
                    if(j-1 >= 0 && k+1 < 2) //甩後噴
                        dp[i][j][k] = min(dp[i][j][k], dp[i-1][j-1][k+1]+10+x);
                }
            }
            dp[i][0][0] = min(dp[i][0][0], dp[i-1][2][0]+10+x);
            dp[i][0][1] = min(dp[i][0][1], dp[i-1][2][0]+10+2*x);
            dp[i][0][1] = min(dp[i][0][1], dp[i-1][2][1]+10+x);
            dp[i][0][2] = min(dp[i][0][2], dp[i-1][2][1]+10+2*x);
        }
        long long res = oo;
        for(i = 0; i < 3; i++)
            for(j = 0; j < 3; j++)
                res = min(res, dp[n-1][i][j]);
        printf("%lld\n", res);
    }
    return 0;
}