传送门
解题思路
设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为山谷)的方案数
最后答案就是
为什么要 \(\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;
}