P3205 [HNOI2010]合唱队

P3205 [HNOI2010]合唱队

题目描述

为了在即将到来的晚会上有更好的演出效果,作为 (AAA) 合唱队负责人的小 (A) 需要将合唱队的人根据他们的身高排出一个队形。假定合唱队一共 (n) 个人,第 (i) 个人的身高为 (h_i)​ 米 ((1000 le h_i le 2000)),并已知任何两个人的身高都不同。假定最终排出的队形是 (A) 个人站成一排,为了简化问题,小 (A) 想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终棑排出的队形中:

第一个人直接插入空的当前队形中。

对从第二个人开始的每个人,如果他比前面那个人高((h) 较大),那么将他插入当前队形的最右边。如果他比前面那个人矮((h) 较小),那么将他插入当前队形的最左边。

(n) 个人全部插入当前队形后便获得最终排出的队形。

例如,有 (6) 个人站成一个初始队形,身高依次为 (1850, 1900, 1700, 1650, 1800, 1750),那么小 (A) 会按以下步骤获得最终排出的队形:

(1850)

(1850, 1900),因为 (1900 > 1850)

(1700, 1850, 1900),因为 (1700 < 1900)

(1650, 1700, 1850, 1900),因为 (1650 < 1700)

(1650, 1700, 1850, 1900, 1800),因为 (1800 > 1650)

(1750, 1650, 1700, 1850, 1900, 1800),因为 (1750 < 1800)

因此,最终排出的队形是 (1750, 1650, 1700, 1850, 1900, 1800)

(A) 心中有一个理想队形,他想知道多少种初始队形可以获得理想的队形。

请求出答案对 (19650827) 取模的值。

输入格式

第一行一个整数 (n)
第二行 (n) 个整数,表示小 (A) 心中的理想队形。

输出格式

输出一行一个整数,表示答案 (mod 19650827) 的值。

输入输出样例

输入 #1

4
1701 1702 1703 1704

输出 #1

8

说明/提示

对于 (30\%) 的数据,(n le 100)
对于 (100\%) 的数据,(n le 1000)(1000 le h_i le 2000)

Solution

分析题目性质我们可以发现,随着越来越多的人加入到合唱队形中,(A) 的理想队形是逐渐向两端扩增的。
假如说我们已经排好了 ([l,r]) 的队形,再加入一个人后的理想队形我们就排好了 ([l-1,r])([l,r+1]),像这样,每一步操作都使我们的目标区间发生有规律的变化,我们应该用区间(dp)来解决。
因为题目中有在左边插入在右边插入两种情况,所以我们开两个数组来分别记录两种情况。

状态设置:

(f1[l][r]) 我们已经排好了 ([l,r]) 的理想队形,且最后一个人插在了最左边的方案数。(f2[l][r]) 为插在了最右边的方案数。

状态转移:

发现当前这个人是插在最左边和最右边取决于他与上个人的身高差,而上个人又分为最左边和最右边两种情况,所以我们要分四种情况讨论:
(1.) 当前的人比上一个人矮,上一个人被插在了最左边。故当前这个人需要插到最左边,即 (l) 的位置,且上一个人是 (a[l+1]),所以有 (f1[l][r]+=f1[l+1][r](a[l]<a[l+1]))
(2.) 当前的人比上一个人矮,上一个人被插在了最右边。故当前这个人需要插在最左边,即 (l) 的位置,且上一个人是 (a[r]),所以有 (f1[l][r]+=f2[l+1][r](a[l]<a[r]))
(3.) 当前的人比上一个人高,上一个人被插在了最左边。故当前这个人需要插在最右边,即 (r) 的位置,且上一个人是 (a[l]),所以有 (f2[l][r]+=f1[l][r-1](a[r]>a[l]))
(4.) 当前的人比上一个人高,上一个人被插在了最右边。故当前这个人需要插在最右边,即 (r) 的位置,且上一个人是 (a[r-1]),所以有 (f2[l][r]+=f2[l][r-1](a[r]>a[r-1]))

边界条件

排好一个人的方案数为 (1),但注意我们不能让 (f1[i][i])(f2[i][i]) 同时为 (1),因为你不能认为他既是从左边插入也是从右边插入,这样会算重。

答案输出

排完 ([1,n]) 的理想队列,最后一个人插在左边和插在右边的方案数之和。
(f1[1][n]+f2[1][n])

(Code)

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
inline ll read()
{
	char ch=getchar();
	ll a=0,x=1;
	while(ch<'0'||ch>'9') 
	{
		if(ch=='-') x=-x;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		a=(a<<1)+(a<<3)+(ch^48);
		ch=getchar();
	}
	return a*x;
}
const ll N=1005;
const ll M=19650827;
ll n;
int a[N];
ll f1[N][N],f2[N][N];
int main()
{
	n=read();
	for(ll i=1;i<=n;i++) a[i]=read();
	for(ll i=0;i<=n;i++) f2[i][i]=1;
	for(ll len=2;len<=n;len++)
	{
		for(ll l=1;l+len-1<=n;l++)
		{
			ll r=l+len-1;
			if(a[l]<a[l+1]) f1[l][r]+=f1[l+1][r];
			if(a[l]<a[r])   f1[l][r]+=f2[l+1][r];
			if(a[r]>a[l])   f2[l][r]+=f1[l][r-1];
			if(a[r]>a[r-1]) f2[l][r]+=f2[l][r-1];
			f1[l][r]%=M;f2[l][r]%=M;
		}
	}
	printf("%lld
",(f1[1][n]+f2[1][n])%M);
	return 0;
}
原文地址:https://www.cnblogs.com/xcg123/p/13925977.html