洛谷 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;
}
posted @ 2020-12-23 17:40  GsjzTle  阅读(76)  评论(0编辑  收藏  举报