ZOJ 3802 Easy 2048 Again(狀壓dp)

畫船聽雨發表於2014-08-26

這道題的意思就是:2048遊戲變成了只有一行的時候的玩法,可以向左合併。給你一串數字你可以選擇一些加入佇列,和為每個數的和,加上合併成的數字。

解題思路:如果一個序列可以合併那麼它一定是降序的,比如:32,16,8,4否則的話,他是不能合併的此時的和就確定了。比如32, 32, 8,16.後面的16怎麼合併都會比8大,所以是16之前的數字不可能繼續合併下去。通過分析我們可以知道降序序列最多會有12種組合。4096……2.所以每次的時候狀壓這種狀態,每個數字每次有兩個選擇,放入或者並不放入佇列當中。在放的時候在列舉前一種的狀態推到下一個狀態。

如果當前數字比上一個狀態中最小的數字小的話,就可以把這個數字加入這個狀態中,如果大那就這個狀態不會向下推出新狀態了,新狀態的開始也就是x了。(這裡狀壓的序列是降序的所以從最小的列舉就可以了。)相同就不斷的進行合併。

Easy 2048 Again

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Dark_sun knows that on a single-track road (which means once he passed this area, he cannot come back again), there are some underground treasures on each area of the road which has the value of 2, 4, 8 or 16. Dark_sun can decide whether to dig them or not in order to get the highest score. The calculation rule of the total score is similar to the game Flappy 2048.

Dark_sun's bag is like a queue. When he gets a treasure, the treasure will be pushed back into the end of the bag. And the score will add the value of the treasure. For example, when there are treasures on the road in the order of {2, 8, 4, 8} and if Dark_sun decides to dig all of them, he will get the final score of 2+8+4+8=22. And his bag will finally become the sequence of {2, 8, 4, 8}.

If the adjacent treasures in the Dark_sun's bag have the same value, they will mix into a bigger treasure which has the value of their sum (the double value of the previous one). And Dark_sun will get a combo score of the value of bigger treasure. For example in the previous case, if Dark_sun decides to dig only the {2, 8, 8} treasure in sequence. He will get the basic score of 18(2+8+8). And when the last treasure (value 8) is pushed back into his bag, his bag will turn {2, 8, 8} into {2, 16} and he will get a bonus score of 16. And his final score will become 18+16=34 (which is the best strategy in this case.)

Notice that the treasures mix to the bigger one automatically when there are the same adjacent treasures. For example, when there are treasures of {2, 2, 4, 8, 16} on the road, and if Dark_sun decides to dig all of them, he will get the basic score of 32(2+2+4+8+16) and a bonus score of 60(4+8+16+32). At last he will get the total score of 92 and the bag becomes {32}.

Now, Dark_sun wants to get the highest score (no matter what's the treasure in his bag), can you tell him the what's the highest score?

Input

The first line is an integer n, which is the case number. In each case, the first line is an integer L, which is the length of the road.(0 < L ≤ 500) The second line contains L integers which canonly be 2, 4, 8 or 16. This means the value of treasure on each area of the road.

Output

For each case, you should output an integer. The answer is the maximum of the total score which Dark_sun may get.

Sample Input

3
4
2 8 4 8
5
2 2 4 8 16
8
8 4 4 2 8 4 2 2

Sample Output

34
92
116

Hint

In the third sample case, Dark_sun will choose {8,4,4,8,4,2,2}. Firstly, the first three treasures will be combined to 16 and then the {16,8,4,2,2} will become 32. And he will get the basic score 32(8+4+4+8+4+2+2) and the bonus score 84(8+16+4+8+16+32).


#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-10
///#define M 1000100
///#define LL __int64
#define LL long long
///#define INF 0x7ffffff
#define INF 0x3f3f3f3f
#define PI 3.1415926535898
#define zero(x) ((fabs(x)<eps)?0:x)

using namespace std;

const int maxn = 510;
int dp[510][8016];
int num[maxn];

void change(int s, int ss, int k, int x)
{
    if(k == 0)
    {
        dp[s][x] = max(dp[s][x], dp[ss][0]+x);
        return;
    }
    if(dp[ss][k] == 0) return;
    dp[s][k] = max(dp[s][k],dp[ss][k]);
    int y = x;
    int ans = x;
    for(int i = 0; i < 13; i++)
    {
        int now = (1<<i);
        if((k&now) == 0) continue;
        if(now < y) dp[s][x] = max(dp[ss][k]+x, dp[s][x]);
        if(now > y) dp[s][x+k] = max(dp[s][x+k], dp[ss][k]+ans);
        if(now != y) return ;
        y *= 2;
        ans += y;
    }
    dp[s][y] = max(dp[s][y], dp[ss][k]+ans);
}

int main()
{
    int T;
    cin >>T;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) scanf("%d",&num[i]);
        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= 8000; j++) dp[i][j] = 0;
        dp[1][num[1]] = num[1];
        for(int i = 2; i <= n; i++)
            for(int j = 0; j <= 8000; j++)
                change(i, i-1, j, num[i]);
        int Max = 0;
        for(int i = 0; i <= 8000; i++) Max = max(dp[n][i], Max);
        cout<<Max<<endl;
    }
    return 0;
}


相關文章