给一个只含有2、4、8、16的序列,每个位置可以选或不选,必须从前到后选。选到一个数,就可以得到相应的分数。和2048规则相似,两个相邻的相同的数可以合并,并且变成它二倍的数。在这道题目中,合并一次也可以得到被合并数2倍的分数。(比如2 2序列,得到的分数就是2+2+4)
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5334
可以想到是dp,但是这道题的状态数太多了。每个字符都有选和不选,还要记录顺序。。。。但是
可以想到,一个在栈中的数要是想合并,那么它后边的数一定要比它小。比如现在栈中的数是8 4 2,那么再放入一个2就可以合并成16了。但是如果栈中的数是8 2 8,那么前边的8 2就无论如何都合并不了了。
所以我们只要记录当前状态包含哪些数字,数字一定是从大到小的,这样状态数就最多是16*500=8000(2^13=8196)。
dp[i][j]表示到达长度i,状态为j的最高分数。
这道题不用滚动数组会超时。。(初始化的时间太大了)
//#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef double DB;
typedef long long ll;
typedef pair<int, int> PII;
#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
//#define Debug
const DB pi = acos(-1.0);
const DB eps = 1e-6;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const int maxn = 100000 + 10;
int lowbit(int x){
return x & (-x);
}
int T, n, a[505], dp[2][1 << 13];
int main(){
#ifdef Debug
freopen("in.txt", "r", stdin);
#endif // Debug
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
memset(dp, -1, sizeof(dp));
dp[0][0] = 0;
int now = 1;
for(int i=1; i<=n; i++){
for(int j=0; j<(1<<13); j++)if(dp[now ^ 1][j] != -1){
int k = lowbit(j);
dp[now][j] = max(dp[now][j], dp[now ^ 1][j]); ///不选
if(a[i] > k) dp[now][a[i]] = max(dp[now][a[i]], dp[now ^ 1][j] + a[i]);
else if(a[i] < k) dp[now][j | a[i]] = max(dp[now][j | a[i]], dp[now ^ 1][j] + a[i]);
else{
int cur = j, res = dp[now ^ 1][j] + a[i], tmp = a[i];
while(lowbit(cur) == tmp){
tmp <<= 1;
res += tmp;
cur ^= lowbit(cur);
}
dp[now][cur | tmp] = max(dp[now][cur | tmp], res);
}
}
now ^= 1;
}
int ans = 0;
for(int i=0; i<(1<<13); i++)
ans = max(ans, dp[now ^ 1][i]);
printf("%d\n", ans);
}
return 0;
}