BZOJ3692 : 愚蠢的演算法

Claris發表於2016-08-29

兩個函式相同等價於不存在長度為$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;
}

  

相關文章