P3147 [USACO16OPEN]262144 P

第十题 P3147 [USACO16OPEN]262144 P

题目分析

此题为区间 \(DP\) ,却与一般的 \(DP\) 题不同。能够看出是两个相邻区间合并,但是却不知道具体是哪两个区间。

因此,我们需要将区间加入状态描述中。左端点,区间长度,右端点三选二。这里选择左端点和区间长度。

\(dp_{i,j}\) 表示以 \(j\) 为左端点合成数字 \(i\) 的区间长度。当区间长度为 \(0\) 时,表示不存在这样的区间。

则可得到状态转移方程:

\(dp[i][j]=dp[i-1][j]+dp[i-1][j+dp[i-1][j]]\)

code

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,dp[60][270000],ans;
int main(){
	scanf("%d",&n);
	int x;
	for(int i=1;i<=n;i++) scanf("%d",&x),dp[x][i]=1;
	for(int i=2;i<=58;i++){
		for(int j=1;j<=n;j++){
			if(!dp[i][j]) 
				if(dp[i-1][j]&&dp[i-1][j+dp[i-1][j]])//判断两个区间是否存在 
					dp[i][j]=dp[i-1][j]+dp[i-1][j+dp[i-1][j]];
			if(dp[i][j]) ans=max(ans,i);
		}
	} 
	cout<<ans<<endl;
	return 0;
}

\(i\) 的最大值为 \(58\) 是因为 \(2^{18}=262144\) 且范围为 \(1\sim40\)

所以 \(i\) 的最大值为 \(40+18=58\)

summary

算是拓宽了在区间 \(dp\) 解法中的另一种常规思路吧。和 \(ST\) 算法有着异曲同工之妙,也算变相复习了 \(ST\) 算法了。

\(2023.1.29\)

posted @ 2023-01-29 12:14  k_stefani  阅读(16)  评论(0编辑  收藏  举报