bzoj 4361: isn
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;
}