【[USACO16OPEN]262144】

发现这个数列的范围特别大但是值域的范围特别小

于是可以大胆猜测这道题值域肯定需要开到状态里去

又发现\(262144=2^{18}\)这个暗示非常明显啊,暗示这道题跟二进制有关系

其实也没什么关系

\(dp[i][j]\)表示从\(i\)位置开始合并,合并出\(j\)这个数所合并的区间的尾位置在哪里

之后就会发现这个转移非常像倍增

\[dp[i][j+1]=dp[dp[i][j]+1][j] \]

就这样了,暴力合并就可以了

同时值域范围需要开到\(40+log_2{262148}=58\)

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 262145
#define max(a,b) ((a)>(b)?(a):(b))
inline int read()
{
	char c=getchar();
	int x=0;
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9')
		x=(x<<3)+(x<<1)+c-48,c=getchar();
	return x;
}
int dp[maxn][59];
int n,ans;
int main()
{
	n=read();int x;
	for(re int i=1;i<=n;i++) 
		x=read(),ans=max(ans,x),dp[i][x]=i;
	for(re int j=1;j<=57;j++)
	{
		for(re int i=1;i<=n;i++)
		{
			if(dp[i][j]<n&&dp[i][j]) dp[i][j+1]=dp[dp[i][j]+1][j];
			if(dp[i][j+1]) ans=max(ans,j+1);
		}
	}
	std::cout<<ans;
	return 0;
}

posted @ 2019-01-02 12:24  asuldb  阅读(191)  评论(0编辑  收藏  举报