这道题和老张关灯很类似,都是从一个序列的两边进行选取,并且每次的区间( i , j )都表示已经操作过的区间,也就是已经得出该区间最优解的区间,那么接着由小推大,就得出当前这个更大一点的区间的最优值.其中要注意初始化时只需要初始化一边就行,如果两边都处理的话会导致答案错误。
#include <iostream>
using namespace std;
const int mod = 19650827;
const int N = 1010;
int dp[N][N][2], a[N];
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> a[i];
for(int i = 1; i <= n; i ++)
dp[i][i][1] = 1;
for(int len = 2; len <= n; len ++){
for(int i = 1; i + len - 1 <= n; i ++){
int j = i + len - 1;
if(a[i] < a[j]) dp[i][j][0] += dp[i + 1][j][1]; //右端点过来的
if(a[i] < a[i + 1]) dp[i][j][0] += dp[i + 1][j][0];
if(a[j] > a[i]) dp[i][j][1] += dp[i][j - 1][0];
if(a[j] > a[j - 1]) dp[i][j][1] += dp[i][j - 1][1];
dp[i][j][0] %= mod;
dp[i][j][1] %= mod;
}
}
cout << (dp[1][n][0] + dp[1][n][1]) % mod << endl;
return 0;
}