兩個函式相同等價於不存在長度為$3$的下降子序列。
先考慮隨意填的部分,設$f[i][j]$表示考慮了$[i,n]$,下降子序列第$2$項的最小值的是這裡面第$j$個的方案數,轉移則考慮往序列裡插數字,可以通過字尾和優化到$O(n^2)$。
然後考慮已固定的部分,設$g[i][j]$表示考慮了$[i,n]$,下降子序列第$2$項的最小值是$j$的方案數,因為填法唯一,所以直接轉移即可。
時間複雜度$O(n^2)$。
#include<cstdio> const int N=2005,P=1000000007; int n,m,i,j,k,flag,a[N],v[N],b[N],cnt,f[N][N],s[N][N],g[N][N],ans; int main(){ scanf("%d%d",&n,&m); for(i=1;i<=m;i++)scanf("%d",&a[i]),v[a[i]]=1; f[n][0]=1; for(i=n-1;i>m;i--){ for(j=n-i+1;j>1;j--)f[i][j]=(s[i+1][j-1]+1)%P; for(j=n;j;j--)s[i][j]=(s[i][j+1]+f[i][j])%P; f[i][0]=1; } if(!m){ for(i=0;i<=n;i++)ans=(ans+f[1][i])%P; return printf("%d",ans),0; } for(i=1;i<=n;i++)if(!v[i])b[++cnt]=i; for(i=0;i<=n-m;i++)g[m+1][b[i]]=f[m+1][i]; if(m==n)g[n+1][0]=1; for(i=m;i;i--){ for(flag=1,j=i+1;j<=m;j++)if(a[i]>a[j]){flag=0;break;} for(j=1;j<=cnt;j++)if(a[i]>b[j]){flag=0;break;} for(j=0;j<=n;j++){ if(j&&a[i]>j)continue; if(flag)k=flag?j:a[i]; g[i][k]=(g[i][k]+g[i+1][j])%P; } } for(i=0;i<=n;i++)ans=(ans+g[1][i])%P; return printf("%d",ans),0; }