【HNOI2010 DAY1】合唱队

Description

为了在即将到来的晚会上有更好的演出效果,作为AAA合唱队负责人的小A需要将合唱队的人根据他们的身高排出一个队形。假定合唱队一共有N个人,第i个人的身高为Hi毫米(1000<=Hi<=2000),并且已知任何两个人的身高都不同。假定最终排出的队形是N个人站成一排,为了简化问题,小A想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终排出的队形中: 
- 第一个人直接插入空的当前队形中。 
- 对从第二个人开始的每个人, 
- - 如果他比前面那个人高(H较大),那么将他插入当前队形的最右边。 
- - 如果他比前面那个人矮(H较小),那么将他插入当前队形的最左边。 
当N个人全部插入当前队形后便获得最终排出的队形。 
例如,有6个人站成一个初始队形,身高依次为1850,1900,1700,1650,1800和1750,那么小A会按以下步骤获得最终出的队形: 
- 1850 
- 1850,1900 
1700,1850,1900 
1650,1700,1850,1900 
- 1650,1700,1850,1900,,1800 
1750,1650,1700,1850,1900,1800 
因此,最终排出的队形是1750,1650,1700,1850,1900,1800 
小A心中有一个理想队形,他想知道从多少种初始队形出发能通过上述排队的方式获得他心中的理想队形作为最终排出的队形?

Input

第一行是一个正整数N,表示总人数。 
输入文件第二行是用空格隔开的N个正整数,从左到右表示小A心中的理想队形:H1, H2, „, HN。 

输入的数据保证1000≤Hi≤2000且没有相同的H值. 
其中30%的数据满足1≤N≤100,100%的数据满足1≤N≤1000。

Output

仅包含一个数,表示从多少种初始队形出发能通过上述排队的方式获得输入文件中指定的小A心中的理想队形。 
因为满足条件的初始队形数可能很大,所以规定只要输出满足条件的初始队形数mod 19650827的值。

Sample Input

输入样例1:
4
1701 1702 1703 1704
输入样例2:
4
1704 1703 1702 1701

Sample Output

输出样例1:
8

输出样例2:
0

Hint

样例解释: 
8种初始队形分别为 
(1701, 1702, 1703, 1704) 
(1704, 1703, 1702, 1701) 
(1702, 1701, 1703, 1704) 
(1703, 1702, 1701, 1704) 
(1702, 1703, 1701, 1704) 
(1702, 1703, 1704, 1701) 
(1703, 1704, 1702, 1701) 
(1703, 1702, 1704, 1701)


【分析】

我果然还是太弱了 Orz... 拿到这道题后居然想了很久才联想到DP...

分析题目可以知道,初始队形中的连续一段一定对应目标队形中的连续一段。

我们这样定义状态数组:

    f[i][j]表示目标队形中[i,j]这一段最左边(i)是刚放上去的数的方案数

   g[i][j]表示目标队形中[i,j]这一段最右边(j)是刚放上去的数的方案数

那么我们可以得到状态转移方程:

    f[i][j]=f[i+1][j]*(h[i]<h[i+1])+g[i+1][j]*(h[i]<h[j])

    g[i][j]=f[i][j-1]*(h[j]>h[i])+g[i][j-1]*(h[j]>h[j-1])

 再回过头来看这个状态转移方程,如果题目不要求满足条件才可以放在最左边或者最右边,那么就是个单纯的递推:

    f[i][j]=f[i+1][j]+g[i+1][j]       g[i][j]=f[i][j-1]+g[i][j-1]

而题目加上了对高度的限制,所以我们要判断高度来选择是否继承那些方案,这就是决策。

边界:

    f[i][i]=g[i][i]=1    f[i-1][j]=g[i-1][j]=(h[i-1]<h[i])


【代码】

/*
    ID:Ciocio
	LANG:C++
	DATE:2013-12-07
	TASK:Chorus
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define MAXN 1005
#define MODER 19650827

int N;
int h[MAXN];
int f[MAXN][MAXN],g[MAXN][MAXN];

void _init()
{
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
		scanf("%d",&h[i]);
}

void _solve()
{
	for(int i=1;i<=N;i++)
	{
		f[i][i]=g[i][i]=1;
		if(i!=1) f[i-1][i]=g[i-1][i]=(h[i-1]<h[i]);
	}
	for(int k=3;k<=N;k++)
		for(int p=1;p+k-1<=N;p++)
		{
			int i=p,j=p+k-1;
			f[i][j]=f[i+1][j]*(h[i]<h[i+1])+g[i+1][j]*(h[i]<h[j]);
			g[i][j]=f[i][j-1]*(h[j]>h[i])+g[i][j-1]*(h[j]>h[j-1]);
			f[i][j]%=MODER;
			g[i][j]%=MODER;
		}
	cout<<(f[1][N]+g[1][N])%MODER<<endl;
}

int main()
{
	_init();
	_solve();
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值