题目连接
https://www.luogu.com.cn/problem/P3146
分析:
1.
首先大家都玩过2048这个游戏吧(没玩过也没关系,游戏规则很简单),这道题是1维的2048,两个相邻数字可以合并当且仅当两个数字相同,但是这里合并后的数字不是翻倍而是+1,比如1,2,2第二和第三个数字2可以合并,合并之后为1,3.
2.规则明白之后,接下来开始分析,由于我们求的是能通过合并得到的最大数字,但是我们知道两个不同数字是无法合并的,那么怎样让它们可以合并并且不影响答案呢,我们不妨让这些不能合并的数字合并得到一个极小的值,这样就不会对答案造成影响了,比如1,2这两个数本来是不能合并的,我们这里合并它给它一个极小的数-1000000000(越小越好),那么这样既不会对最大值造成影响也不会影响我们合并区间,那么现在关键步骤来了(也是比较抽象的),我们知道一个区间有很多种合并方式,比如[1,1,2]这个区间,我们可以先合并1,1得到2,那么此时区间变为了[2,2],再合并2,2得到3,此时区间就变为了3,但是如果我们先合并1,2得到-100000000,此时区间变成了[1,-1000000000]再合并1,-100000000得到-1000000000,最终得到一个极小数,我们知道一个极小数对于后面的合并都是无意义的,因为极小数和任何数合并都只会是极小数(就算和它本身合并+1,也要合并1000000000次才能超过0,还没有这个初始的区间最大值大,因为初始区间的数范围也在1-40),所以我们不妨用贪心的策略去合并区间,使得这个区间最后得到一个最大的值,然后我们通过不断合并的过程去实时跟新最大值,例如现在给你一个区间[1,1,2],刚开始最大值Max为2,我们通过贪心最优合并能得到最终数字3,那么这个3就是我们区间合并的结果,而不是-1000000000,那么此时Max就跟新为了3,最后输出Max即可.
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int Maxn = 300;
int f[Maxn][Maxn];
int Max = 0;
int main()
{
memset(f,~0x7f7f7f7f,sizeof(f));//全部初始化最小值
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>f[i][i];
Max = max(Max,f[i][i]);//自己和自己合并就是它本身
}
for(int len=1;len<=n;len++)
for(int i=1;i+len-1<=n;i++)
for(int j=i;j<i+len-1;j++)
{
int k = i+len-1;
/*这两个区间f[i][j]和f[j+1][k]能否合并为一个非极小数,
也就是这个两个区间的数是否相等,若不能合并为一个非极小数,
那么就不合并,默认f[i][j]为极小数不做处理,因为之前
以及初始化了所有f数组的值为极小数~0x7f7f7f7f*/
if(f[i][j]==f[j+1][k])
{
f[i][k] = max(f[i][k],f[i][j]+1);//合并
Max = max(Max,f[i][k]); //实时根新最大值Max
}
}
printf("%d",Max);
return 0;
}