[USACO16OPEN]248

Posted by Dispwnl on December 24, 2017

题目

题目大意

给定一个1*n的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问最大能合出多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。

输入输出样例

输入样例#1:

4
1
1
1
2

输出样例#1:

3

题解

可以看出是区间$DP$

对于每一个区间记录的是能构成的最大值

因为是相邻的区间,思路是枚举每一个分界点

即$i$从$2$枚举到$n$

然后枚举$i$前的点$j$和$i$后的点$k$

就构成了两个相邻的区间$f_{j,i-1}$和$f_{i,k}$

$i-1$是因为是相邻的区间,所以$i$只能取一次

如果$f_{j,i-1}=f_{i,k}$,$f_{j,k}=max(f_{j,i-1}+1)$(注意不是$\times 2$,这是$248$不是$2048$)

然后试几组数据会发现答案不对,因为前面的区间可以被后面更新的区间更新

举个例子

$3\;2\;2\;1$

显然最优解是先合并两个$2​$再用合出来的$3​$与原来的$3​$合并

为了解决这一问题,多次循环就好了

保证后面合出来的区间能与前面的区间合并

代码

# include<iostream>
# include<cstdio>
# include<cstring>
using namespace std;
int n;
int f[301][301];
void fre()
{
    //freopen("248.in","r",stdin);
    //freopen("248.out","w",stdout);
}
int main()
{
    fre();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%d",&f[i][i]);
    for(int l=1;l<=10;l++)
      for(int i=2;i<=n;i++)
        for(int j=i-1;j>=1;j--)
          for(int k=i;k<=n;k++)
            if(f[j][i-1]==f[i][k])
            f[j][k]=max(f[j][k],f[j][i-1]+1);
    int maxn=0;
    for(int i=1;i<=n;i++)
      for(int j=i;j<=n;j++)
        maxn=max(maxn,f[i][j]);
    printf("%d",maxn);
    return 0;
}