……

解题报告:luogu P3205

题目链接:P3205 [HNOI2010]合唱队

跟风切题

shy txdy!

手残点了一下标签,看到标签之后就秒了。
区间 \(dp\),注意这是整区间不完全利用性的。
什么意思呢?就是对于继承的区间,里面的元素不一定完全有用。
还记得 ABC163 的 \(E\) 题吗?(不记得可以看这里-->快戳我
有相似之处。
一般有用的是两端,中点或若干个显而易见的位置。
我们考虑设 \(dp_{i,j,0/1}\)\([i,j]\)之中最后选左端点/右端点的方案数,显然:

\[dp_{i,j,0}=dp_{i+1,j,0}×[a_{i}<a_{i+1}]+dp_{i+1,j,1}×[a_i<a_j] \]

\[dp_{i,j,1}=dp_{i,j-1,0}×[a_{j}>a_{i}]+dp_{i,j-1,1}×[a_j>a_{j-1}] \]

最后的得数即为 \(dp_{1,n,0}+dp_{1,n,1}\)

\(Code\):

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

#define read(x) scanf("%d",&x)
#define MOD 19650827
#define ll long long 

int n,a[1005];
ll dp[1005][1005][3];

int main()
{
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) dp[i][i][0]=dp[i][i][1]=1ll;
	for(int i=1;i<=n-1;i++)
	{
		if(a[i]<a[i+1]) dp[i][i+1][0]=dp[i][i+1][1]=1ll;
		else dp[i][i+1][0]=dp[i][i+1][0]=0;
	}
	for(int i=3;i<=n;i++)
	{
		for(int l=1;l+i-1<=n;l++)
		{
			int r=l+i-1;
			if(a[l+1]>a[l]) dp[l][r][0]+=dp[l+1][r][0]%MOD;
			if(a[r]>a[l]) dp[l][r][0]+=dp[l+1][r][1]%MOD;
			if(a[l]<a[r]) dp[l][r][1]+=dp[l][r-1][0]%MOD;
			if(a[r-1]<a[r]) dp[l][r][1]+=dp[l][r-1][1]%MOD;
		}
	}
	printf("%lld\n",(dp[1][n][0]+dp[1][n][1])%MOD);
	return 0;
}
posted @ 2020-04-28 22:05  童话镇里的星河  阅读(120)  评论(0编辑  收藏  举报