P3205 [HNOI2010]合唱队

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3205 [HNOI2010]合唱队相关的知识,希望对你有一定的参考价值。

P3205 [HNOI2010]合唱队

题意:

有n个数,然后插入队伍中,如果队列当前为空,则直接插入,然后每次插入和上一次插入的比较,如果大于,插入当前队列的最右侧,如果小于,插入当前队列的最左侧
现在给你一个插入后的队形,问有多少种插入方式?

题解:

我们这样分析,对于区间[l,r],最近一次插入的要么是第l位要么就是第r位
所以我们设f[i][j]表示可以排成理想队列中[i,j]区间,且以最后一个排进去是第i人的初始队列种数。
设g[i][j]表示可以排成理想队列中[i,j]区间,且以最后一个排进去是第j人的初始队列种数。
我们考虑f[i][j],第i位是本次刚插入的,那上一个插入的位置可能是在第i+1位或者是第j位,第i+1位的话就是上一次插入的是最左侧,第j位的话就是上一次插入的是最右侧,所以f[i][j]可以由f[i+1][j]和g[i+][j]得到,前提是a[i]要小于a[i+1],或者a[i]小于a[j],因为第i位插入到最左侧,所以肯定是小于上次插入
同理对g[i][j]也可以推导出相应公式
最终为:

代码:

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;

inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=1e3+9;
const int mod=19650827;
int a[maxn];
int f[maxn][maxn],g[maxn][maxn];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)f[i][i]=1;
	for(int len=1;len<=n;len++){
		for(int i=1;i+len-1<=n;i++){
			int j=i+len-1;
			if(a[i]<a[i+1])//如果上一次进来的是第i+1位 
				f[i][j]+=f[i+1][j];
			if(a[i]<a[j])//如果上一次进来的是第j位 
				f[i][j]+=g[i+1][j];
				 
			if(a[j]>a[i])//如果上一次进来的是第 i位 
				g[i][j]+=f[i][j-1];
			if(a[j]>a[j-1])//如果上一次进入的是第j-1位 
				g[i][j]+=g[i][j-1];
				f[i][j]%=mod;
				g[i][j]%=mod;
		}
	}
	cout<<(f[1][n]+g[1][n])%mod; 
	return 0;
}

以上是关于P3205 [HNOI2010]合唱队的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 [P3205] 合唱队

luogu P3205 合唱队

1996: [Hnoi2010]chorus 合唱队

bzoj 1996: [Hnoi2010]chorus 合唱队

bzoj1996: [Hnoi2010]chorus 合唱队 区间dp

BZOJ1996[Hnoi2010]chorus 合唱队 区间DP