题目链接
思路:
我们发现,对于目标序列的每一个区间
[
l
,
r
]
[l, r]
[l,r]而言,最后一个进来这个区间的人要么在
l
l
l要么在
r
r
r,那么我们可以定义
f
[
l
,
r
,
0
]
f[l,r, 0]
f[l,r,0]表示最后一个人从左边进入目标序列的
[
l
,
r
]
[l,r]
[l,r]区间的所有方案数,
f
[
l
,
r
,
1
]
f[l,r,1]
f[l,r,1]表示最后一个人从右边进入目标序列的
[
l
,
r
]
[l,r]
[l,r]区间的所有方案数。我们考虑转移:
首先考虑
f
[
l
,
r
,
0
]
f[l,r,0]
f[l,r,0],由于最后一个人从左边进入序列,那么他的位置为
l
l
l,那么倒数第二个人可能的位置为
l
+
1
l + 1
l+1和
r
r
r,如果
h
[
l
]
<
h
[
l
+
1
]
h[l] < h[l + 1]
h[l]<h[l+1]那么
f
[
l
,
r
,
0
]
f[l,r,0]
f[l,r,0]可以从
f
[
l
+
1
,
r
,
0
]
f[l + 1,r,0]
f[l+1,r,0]转移来;如果
h
[
l
]
<
h
[
r
]
h[l] < h[r]
h[l]<h[r],那么
f
[
l
,
r
,
0
]
f[l,r,0]
f[l,r,0]可以从
f
[
l
+
1
,
r
,
1
]
f[l + 1,r,1]
f[l+1,r,1]转移来。
同理,对于
f
[
l
,
r
,
1
]
f[l,r,1]
f[l,r,1],如果
h
[
r
]
>
h
[
l
]
h[r] > h[l]
h[r]>h[l],那么
f
[
l
,
r
,
1
]
f[l,r,1]
f[l,r,1]可以从
f
[
l
,
r
−
1
,
0
]
f[l,r - 1,0]
f[l,r−1,0]转移来;
如
果
h
[
r
]
>
h
[
r
−
1
]
如果h[r] > h[r - 1]
如果h[r]>h[r−1],那么
f
[
l
,
r
,
1
]
f[l,r,1]
f[l,r,1]可以从
f
[
l
,
r
−
1
,
1
]
f[l,r-1,1]
f[l,r−1,1]转移来。
初始化所有
f
[
i
,
i
,
0
]
f[i,i,0]
f[i,i,0]为
1
1
1,其余为
0
0
0,就是默认只有一个人只能从左边进序列。
目标状态为
f
[
1
,
n
,
0
]
+
f
[
1
,
n
,
1
]
f[1,n,0] + f[1,n,1]
f[1,n,0]+f[1,n,1]
AC代码:
#include <iostream>
using namespace std;
const int N = 1005, mod = 19650827;
int n;
int h[N];
int f[N][N][2];
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> h[i];
for (int i = 1; i <= n; i ++ ) f[i][i][0] = 1;
for (int i = 1; i <= n; i ++ )
for (int l = 1; l + i - 1 <= n; l ++ )
{
int r = l + i - 1;
if (h[l] < h[l + 1]) f[l][r][0] += f[l + 1][r][0];
if (h[l] < h[r]) f[l][r][0] += f[l + 1][r][1];
if (h[r] > h[l]) f[l][r][1] += f[l][r - 1][0];
if (h[r] > h[r - 1]) f[l][r][1] += f[l][r - 1][1];
f[l][r][0] %= mod;
f[l][r][1] %= mod;
}
cout << (f[1][n][0] + f[1][n][1]) % mod << endl;
return 0;
}