很快看出來是區間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;
}