很快看出来是区间dp,搞了个O(n^3)的dp方程,0/1状态表示当前区间的首/尾作为末尾,然后搞记忆化搜索半天没搞出来,还得搞个RMQ,于是百度了题解(为毛题解都长的一样,还都是WA的。。。这群人抄也不抄仔细点。。。)
题解大概就是通过一个个数插入将区间向两边扩大,而且只能放在两头,条件就是上一个放的数值和这个数的数值满足题意。讨论一下就好了,dp方程写出来还是很简单的。(其实就是将我的思路改进一下,不合并区间与区间,合并区间与数)
这里需要注意枚举区间i,j的方向,由于i+1向i拓展,j-1向j拓展,于是i+1应该在i之前,于是i指针应该倒序,同理j应该升序。
注意状态转移的方向和枚举的方向是相反的!
其次就是初值,观察列出的dp方程,发现如果j==i+1时,dp[i][i]和dp[j][j]会向dp[i][j]加两遍(因为dp[i][i]无序),所以初值只任意设一个就好了。
还有就是必须得吐槽一下网上的代码,照着写了半天,交上去WA了一屏。结果把网上的原码交上去照样WA。爆int是要闹哪样啊。。。一份两份全都爆int是要闹哪样啊(雾)。。。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1005;
const int mod=19650827;
int n;
int s[maxn];
long long dp[maxn][maxn][2];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",s+i),
dp[i][i][1]=1;//只选0/1中一个赋值
for(int i=n;i;i--)
for(int j=i+1;j<=n;j++)
{
if(s[i]<s[j])dp[i][j][1]+=dp[i][j-1][0];
if(s[i]<s[j])dp[i][j][0]+=dp[i+1][j][1];
if(s[i+1]>s[i])dp[i][j][0]+=dp[i+1][j][0];
if(s[j]>s[j-1])dp[i][j][1]+=dp[i][j-1][1];
dp[i][j][0]%=mod;dp[i][j][1]%mod;
}
printf("%d",(dp[1][n][0]+dp[1][n][1])%mod);
return 0;
}