传送门


解题思路

设dp[i][j]表示用前i个数,第一段山脉的高度为j,且j为山峰的方案数。
首先发现,dp[i][j]=dp[i][i-j+1],相当于把每个数取了个相反数,原来的山峰变山谷,山谷变山峰,方案数不变。
然后状态转移:

  • j和j-1不相邻时:dp[i][j]=dp[i][j-1] 因为交换j和j-1,对其他的点没有影响。
  • j和j-1相邻时:dp[i][j]=dp[i-1][(i-1)-(j-1)+1] 可以看做除去第一个数j,剩下的i-1个数(以j-1开头,且j-1为山谷)的方案数

最后答案就是

\[ans=2\times\sum_{j=1}^{n}dp[n][j] \]

为什么要 \(\times2\) 呢?因为sum只统计了第一个山作为山峰的方案数,而山谷的方案数与其相等。
再加上滚动数组优化一下即可。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
int n,p,dp[2][4205];
long long ans;
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>p;
	dp[1][1]=1;
	for(int i=2;i<=n;i++){
		for(int j=1;j<=i;j++){
			dp[i&1][j]=(dp[i&1][j-1]+dp[(i-1)&1][(i-1)-(j-1)+1])%p;
		}
	}
	for(int i=1;i<=n;i++) ans+=dp[n&1][i];
	cout<<ans*2%p;
    return 0;
}