[USACO16OPEN]248
题目
Description
Bessie likes downloading games to play on her cell phone, even though she doesfind the small touch screen rather cumbersome to use with her large hooves.
She is particularly intrigued by the current game she is playing.The game starts with a sequence of N positive integers (2≤N≤248), each in the range 1…40. In one move, Bessie cantake two adjacent numbers with equal values and replace them a singlenumber of value one greater (e.g., she might replace two adjacent 7swith an 8). The goal is to maximize the value of the largest numberpresent in the sequence at the end of the game. Please help Bessiescore as highly as possible!
给定一个1*n的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问最大能合出多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。
Input
The first line of input contains N, and the next N lines give the sequence
of N numbers at the start of the game.
Output
Please output the largest integer Bessie can generate.
Sample Input
4 1 1 1 2
Sample Output
3
Hint
In this example shown here, Bessie first merges the second and third 1s to
obtain the sequence 1 2 2, and then she merges the 2s into a 3. Note that it is
not optimal to join the first two 1s.
思路
这是一道有点不错的区间$dp$ 题;
强化版请见 [USACO16OPEN]262144
我们可以设 $dp[i][j]$ 表示可以合成的 区间$[i,j]$ 合成的最大值;
注意是表示可以合成的区间;
比如样例 : $1, ~1,~1,~2$ ;
可合成的区间是 $[1,2]$,而 $[3,4]$ 就不是一个可合成的区间,因为其中是不同的,要求是相同的值则可合成;
可合成的区间要求这个区间定是通过不断合成,能剩下一个数;
那么这样转移方程就好写了;
由于博主过于蒟蒻,一开始设的 $dp[i][j]$ ,表示所有的区间,然后一直考虑数字的位置相邻怎么解决,后来脑子才开窍,换成这种思路;
那么设成可合成的区间,就不需要考虑相邻怎么解决;
我们只需要在转移的时候判断, $dp[i][k]$ 等于 $dp[k+1][j]$ 时转移 ;
还要注意的是,我们设的 $dp[i][j]$ 是可合成的区间,那么不可合成的区间的值就不会被更新,所以我们还需判断 $dp[i][k]$ 和 $dp[k+1][j]$ 都不为 $0$ ;
那么转移方程就是
$dp[i][j]=max(dp[i][j],dp[i][k]+1)$ ;
这样就 $ok$ 了;
代码
#include<bits/stdc++.h> #define re register typedef long long ll; using namespace std; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n; ll dp[300][300]; int main() { n=read(); for(re ll i=1;i<=n;i++) dp[i][i]=read();//直接读入 for(re ll len=2;len<=n;len++)//枚举区间长度 for(re ll i=1;i<=n-len+1;i++)//枚举区间起点 { ll j=i+len-1;//区间终点 for(re ll k=1;k<=n;k++)//枚举区间断点 if(dp[i][k]==dp[k+1][j]&&dp[i][k])//判断两区间可以合成 dp[i][j]=max(dp[i][j],dp[i][k]+1);//更新答案 } ll ans=0; for(re ll i=1;i<=n;i++) for(re ll j=1;j<=n;j++) ans=max(ans,dp[i][j]);//统计答案 printf("%lld\n",ans);//输出 //return 0; }