【HNOI】合唱队

【HNOI】合唱队

题意

对于一个初始序列,保证两两不同,通过一些变换得到目标序列:
第一个值直接插入空的当前队列
对于从第二个值开始的每个值
如果原序列中 $ a[i] $,若 $ a[i]>a[i-1]$ ,那么插入新队列的最右边
如果原序列中 \(a[i]\),若 \(a[i]<a[i-1]\),那么插入新队列的最左边
给定目标序列,问有多少个初始序列按照上述方式变化后可以得到目标序列
\(1000<=Hi<=2000\)\(1<=N<=1000\)

解法

设 $ f[i][j][0/1]$表示第 i~j 区间内的最后一个点是从左边加进来还是从右边加进来,然后就可以转移了。

注意 : 为了满足无后效性,需要先枚举区间的长度。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=1000+5;
const int mod=19650827;
int a[maxn];
int f[maxn][maxn][2];
int n;
int main()
{
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) f[i][i][0]=1;
	for(int l=2;l<=n;l++){
		for(int j=l;j<=n;j++){
			int i=j-l+1;
			if(a[i]<a[j]) f[i][j][1]+=f[i][j-1][0];
			if(a[i]<a[j]) f[i][j][0]+=f[i+1][j][1];
			if(a[i]<a[i+1]) f[i][j][0]+=f[i+1][j][0];
			if(a[j]>a[j-1]) f[i][j][1]+=f[i][j-1][1];
			f[i][j][1]%=mod;
			f[i][j][0]%=mod;
		}
	}
	printf("%d",(f[1][n][0]+f[1][n][1])%mod);
	return 0;
}
posted @ 2018-08-22 20:42  Mr_asd  阅读(197)  评论(0编辑  收藏  举报