码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4361: isn

时间:2018-02-10 20:09:26      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:ace   namespace   include   inline   长度   停止   stdin   amp   操作   

Description

给出一个长度为n的序列A(A1,A2...AN)。如果序列A不是非降的,你必须从中删去一个数,
这一操作,直到A非降为止。求有多少种不同的操作方案,答案模10^9+7

Solution

删除操作做完之后的序列,是原串的一个子序列,如果我们直到子序列长度为 \(i\),那么要把其他 \(n-i\) 个数删除,现在就只需要关心子序列的长度了
删除的总方案为 \((n-i)!\),但是由于A非降时就会停止,所以可能到了非降时还没有停止,所以要减去不合法的
设通过删除操作变成长度为\(i\)的子序列的总方案(包括不合法)子序列有 \(g[i]\) 个,合法的有 \(f[i]\)
那么 \(f[i]=g[i]-g[i+1]*(i+1)\),长度为 \(i+1\) 的每一个不降子序列去掉一个就变成了长度为 \(i\)
求所有子序列可以用树状数组维护

#include<bits/stdc++.h>
using namespace std;
const int N=2010,mod=1e9+7;
int n,a[N],f[N][N],tr[N][N],b[N],m,g[N],Fac[N];
inline int qry(int x,int sta){
  int ret=0;
  for(int i=sta;i>=1;i-=(i&(-i)))ret=(ret+tr[x][i])%mod;
  return ret;
}
inline void add(int x,int sta,int t){
  for(int i=sta;i<=m;i+=(i&(-i)))tr[x][i]=(tr[x][i]+t)%mod;
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d",&n);
  for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
  sort(b+1,b+n+1);m=unique(b+1,b+n+1)-b-1;
  for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+m+1,a[i])-b;
  add(0,1,1);
  for(int i=1,t;i<=n;i++)
    for(int j=i;j>=1;j--)
      t=qry(j-1,a[i]),f[a[i]][j]=(f[a[i]][j]+t)%mod,add(j,a[i],t);
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      g[i]=(g[i]+f[j][i])%mod;
  int ans=0;
  Fac[0]=1;for(int i=1;i<=n;i++)Fac[i]=1ll*Fac[i-1]*i%mod;
  for(int i=1;i<=n;i++)g[i]=1ll*Fac[n-i]*g[i]%mod;
  for(int i=1;i<=n;i++){
    if(g[i+1])g[i]=(g[i]-1ll*g[i+1]*(i+1))%mod;
    if(g[i])ans=(ans+g[i])%mod;
  }
  if(ans<0)ans+=mod;
  cout<<ans<<endl;
  return 0;
}

bzoj 4361: isn

标签:ace   namespace   include   inline   长度   停止   stdin   amp   操作   

原文地址:https://www.cnblogs.com/Yuzao/p/8439587.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!