洛谷 P3205
题目链接
题目大意
给定一串序列,问有多少种初始序列经过以下操作可以得到此序列:
① 、第一个数直接插入空的当前序列中
② 、对从第二个数开始的每个数,如果它比上一个插入序列的数大,那么将它插入当前序列的最右边
如果它比上一个插入序列的数小,那么将它插入当前序列的最左边
解题思路
定义 \(dp1[i][j]\) 的含义为构成理想区间\([i , j]\) ,最后一个被放入的是 \(i\) 的方案数
定义 \(dp2[i][j]\) 的含义为构成理想区间\([i , j]\) ,最后一个被放入的是 \(j\) 的方案数
一、
对于 \(dp1\)
区间 \([i , j]\) 的上一个区间为 \([i + 1 , j]\)
而构成区间 \([i + 1][j]\) 的序列的末尾可能是 \(a[i + 1]\) ,也可能是 \(a[j]\)
所以:
①.当 \(a[i] < a[i + 1]\) 时 , \(dp1[i][j] += dp1[i + 1][j]\)
②.当 \(a[i] < a[j]\) 时 , \(dp1[i][j] += dp2[i + 1][j]\)
二、
对于 \(dp2\)
区间 \([i , j]\) 的上一个区间为 \([i , j - 1]\)
而构成区间 \([i][j - 1]\) 的序列的末尾可能是 \(a[i]\) ,也可能是 \(a[j - 1]\)
①.当 \(a[j] > a[i]\) 时 , \(dp2[i][j] += dp1[i][j - 1]\)
②.当 \(a[j] > a[j - 1]\) 时 , \(dp2[i][j] += dp2[i][j - 1]\)
最后 $ans = dp1[1][n] + dp2[1][n] $
注意:当 \(i = j\) 即区间长度为 \(1\) 时 , 只需让 \(dp1 = 1\) or \(dp2 = 1\) 即可
即构造区间长度为 \(1\) 的方案数只有 \(1\)
若让 \(dp1\) 和 \(dp2\) 都等于 \(1\) 则相当于构造区间长度为 \(1\) 的方案数为 \(1 + 1 = 2 (×)\)
AC_Code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10 , mod = 19650827;
int n , a[N];
int dp1[N][N] , dp2[N][N];
signed main()
{
cin >> n;
for(int i = 1 ; i <= n ; i ++) cin >> a[i] , dp1[i][i] = 1;
for(int len = 1 ; len <= n ; len ++)
{
for(int i = 1 ; i + len <= n ; i ++)
{
int j = i + len;
{
if(a[i] < a[i + 1]) dp1[i][j] += dp1[i + 1][j];
if(a[i] < a[j]) dp1[i][j] += dp2[i + 1][j];
if(a[j] > a[i]) dp2[i][j] += dp1[i][j - 1];
if(a[j] > a[j - 1]) dp2[i][j] += dp2[i][j - 1];
dp1[i][j] %= mod , dp2[i][j] %= mod;
}
}
}
cout << (dp1[1][n] + dp2[1][n]) % mod << '\n';
return 0;
}