USACO 2016 US Open【262144游戏】

Description

Bessie喜欢在手机上下载游戏玩(……),然而她蹄子太大,很难在小小的手机屏幕上面操作。

她被她最近玩的一款游戏迷住了,游戏一开始有n个正整数,(2<=n<=262144),范围在1-40。每一步中,贝西可以选相邻的两个相同的数,然后合并成一个比原来的大一的数(例如两个7合并成一个8),直到不能合并,游戏结束,目标是使得最后最大的数最大,请帮助Bessie来求最大值。

Input Format

输入格式:(262144.in)

第一行n,然后n行分别是开始游戏时每一个数。

Output Format

输出格式:(262144.out)

Bessie能生成的最大的数。

Sample Input

4
1
1
1
2

Sample Output

3

Hint

样例解释

将第二个和第三个1合并成2,然后两个2合并成3。

过程:

1 1 1 2

1 2 2

1 3

【题解】

一题 题目不水,数据很水的动归题(说数据水是因为,随便搞搞都能过,貌似各种不正确贪心,甚至是正反两遍for能和则和,也能过 )

个人觉得这题很类似于倍增的前期预处理(f[i][j]=f[f[i][j-1]][j-1])(不知道为啥很多人觉得像合并类动归)

仔细思考不难发现,本题一个区间内的数不一定可以完全合并,因此,状态单记录合成数值,或者区间范围是不可取的

因此状态设计时必须强制使得一段区间内的所有数都被合并,看一下数据范围如果把区间的两个端点都表示在状态里面也是不可取的(爆内存啊)

后来发现其实一段区间完全合并数字是确定的,所以知道了一个端点知道合并出来的值另一个端点也就确定了,刚好数字又特别小(最多就58)所以就在状态里面表示一个端点和所合成的数值,那状态就设计出来了233(f[j][i])表示以第j个数为左端点数值为i时右端点的位置

所以就出现了一个与倍增特别相似的转移方程f[j][i]=f[f[j][i-1]+1][i-1] 然后程序就特别好写了初始值就是f[i][a[i]]=i;

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int i,j,k,l,m,n;
int f[262200][65],a[262200];
int main()
  {
  	scanf("%d",&n);
  	for (i=1;i<=n;i++) scanf("%d",&a[i]),f[i][a[i]]=i,m=max(m,a[i]);
  	for (i=1;i<=m;i++)
  	  {
  	  	for (j=1;j<=n;j++)
  	  	  if (f[j][i]!=0&&f[f[j][i]+1][i]!=0) 
  	  	    {
				f[j][i+1]=f[f[j][i]+1][i];
				if (i+1>m) m=i+1;
		    }
	  }
	printf("%d",m);
  }


你可能感兴趣的:(usaco,动态规划)