luogu P3205 合唱队
Posted charlesss
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3205 合唱队相关的知识,希望对你有一定的参考价值。
又一道区间的dp。
状态dp[i][j]表示队列中i——j可行的排列方法。
首先定义边界:对于每一个点,dp[i][i]=1(显然)
然后导一下状态转移方程,大区间必然由小区间转移而来,但是转移方法可以有多种。完成区间排列的最后一步,既可以由在左边插入i完成,也可以通过在右边插入j完成。
方便判断,在状态上再加一维,即dp[i][j][0/1],最后一维为0则从左插入i,为1则从右插入j。
每个状态只跟上一个状态有关,但上一个状态并不确定是从左还是右插入,因此需要进行分类讨论:
当右端点的数大于上一个且上一个插入在右端时:f[ i ][ j ][ 1 ] += f[ i ][j - 1][ 1 ];
当右端点的数大于左端点且上一个插入在左端时:f[ i ][ j ][ 1 ] += f[ i ][ j - 1 ][ 0 ];
当左端点的数小于后一个且上一个插入在左端时:f[ i ][ j ][ 0 ] += f[ i + 1 ][ j ][ 0 ];
当左端点的数小于右端点且上一个插入在右端时:f[ i ][ j ][ 0 ] += f[ i + 1 ][ j ][ 1 ];
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n[1005],dp[1005][1005][2];
int main()
{
int a;
cin>>a;
for(int i=1;i<=a;i++)
cin>>n[i];
for(int i=1;i<=a;i++)
dp[i][i][0]=1;
for(int l=2;l<=a;l++)
{
for(int i=1;i<=a-l+1;i++)
{
int j=i+l-1;
if(n[j]>n[j-1])
dp[i][j][1]+=dp[i][j-1][1];
if(n[j]>n[i])
dp[i][j][1]+=dp[i][j-1][0];
if(n[i]<n[i+1])
dp[i][j][0]+=dp[i+1][j][0];
if(n[i]<n[j])
dp[i][j][0]+=dp[i+1][j][1];
dp[i][j][0]%=19650827;
dp[i][j][1]%=19650827;
}
}
cout<<((dp[1][a][0]+dp[1][a][1])%19650827);
return 0;
}
以上是关于luogu P3205 合唱队的主要内容,如果未能解决你的问题,请参考以下文章