BZOJ3692 : 愚蠢的算法

两个函数相同等价于不存在长度为$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;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/5818817.html