您的位置:首页 > 其它

2014新生暑假个人排位赛03 E. 学姐的数列

2014-07-25 17:10 483 查看


E. 学姐的数列

时间限制 5000 ms 内存限制 65536
KB


题目描述

定义一颗平衡二叉树满足条件:对于任意节点,其左子树的权值之和等于右子树权值之和。如图:



我们用序列表示上图平衡二叉树,即4 1 1 2 4 4。

现在给定一个序列,求其能最长的能构成平衡二叉树的子序列。子序列元素为原序列的子集,且元素间保持原顺序。


输入格式

输入第一行为数据组数T(T≤10),接下来T组数据,每组第一行n(1≤n≤128)为序列元素个数,下一行给出n个正整数,ai(ai≤7)表示第i个数为2^ai。


输出格式

每组数据输出一行,符合题意的最长子序列的长度。


输入样例

2
6
2 0 0 1 2 2
5
0 0 0 0 0



输出样例

6
4


n^3 dp暴力,设dp[i][j][w]为区间[i,j]上和为2^w的最大长度,不难得出,dp[i][j][w]=max(dp[i][k][w-1]+dp[k+1][j][w-1])(i<=k<j),初始化为dp[i][j][a[t]]=1,(i<=t<=j)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int maxn = 140;

int dp[maxn][maxn][20];

int main()
{
#ifdef LOCAL
freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif

int T;
scanf("%d", &T);
while(T--)
{
int n;
int a[maxn];
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}

memset(dp, 0, sizeof(dp));

for(int i = 0; i < n; i++)
for(int j = i; j < n; j++)
for(int k = i; k <= j; k++)
{
dp[i][j][a[k]] = 1;
}

for(int k = 1; k < 15; k++)
for(int i = 0; i < n; i++)
for(int j = i+1; j < n; j++)
for(int t = i; t < j; t++)
{
if(!dp[i][t][k-1]||!dp[t+1][j][k-1])//这个判断不能省!
continue;
if(dp[i][j][k] < dp[i][t][k-1] + dp[t+1][j][k-1])
dp[i][j][k] = dp[i][t][k-1] + dp[t+1][j][k-1];
}

int ans = 0;

for(int k = 0; k < 15; k++)
{
ans = max(ans, dp[0][n-1][k]);
}

printf("%d\n", ans);

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: