解题思路
一个能够恰好分成若干部分
,并且每个部分恰好为连续数
。
子序列特征:最大值减最小值
等于左端点减右端点
O
(
n
2
)
O(n^2)
O(n2)
暴力搜索:枚举每一个左端点和每一个右端点
动态规划:定义状态
d
p
(
i
)
dp(i)
dp(i)表示最后一个部分以第i个数字结尾
的方案数。
状态转移
1、考虑以第
i
i
i个数字为最后一个部分的右端点端点,
2、枚举最后一个部分的左端点
j
j
j,当满足左端点
j
j
j到右端点
i
i
i之间的区间是连续数,我们则认为是合法的。于是dp(i)可以通过
d
p
(
j
−
1
)
dp(j-1)
dp(j−1)转移过来,最后一部分表示的区间为
[
j
,
i
]
[j , i]
[j,i]。
转移方程式如下
d p ( i ) = ∑ j = 1 i d p ( j − 1 ) [ j − i = = m a x ( a k ) − m i n ( a k ) ] , k ∈ ( i , j ) , j ∈ ( 1 , i ) dp(i) = \sum_{j=1}^i dp(j - 1)[j - i == max(a_k) - min(a_k) ], \\ k \in (i,j), j \in (1,i) dp(i)=j=1∑idp(j−1)[j−i==max(ak)−min(ak)],k∈(i,j),j∈(1,i)
时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
Code(Python3)(TLE)
由于 python 语言本身执行效率较低,故采用上述解法的 python 代码提交的结果是超时。经过时间测试,该代码完成最大测试用例的时间在 22s 左右。
# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
MOD=int(1e9+7)
n=int(input())
w=[0]
dp=[0]*(n+1)
w.extend([int(i) for i in input().split()])
dp[0]=1
maxn,minn=0,int(1e9)
for i in range(1,n+1):
maxn,minn=0,int(1e9)
for j in range(i,0,-1):
maxn=max(maxn,w[j])
minn=min(minn,w[j])
if maxn-minn==i-j:
dp[i]=(dp[i]+dp[j-1])%MOD
print(dp[n])