题意
给出一个数列(a),当这个数列不是不下降的时候我们删除其中一个数,直到它是不下降的。
问有多少种删除方案。(nle 2000)。
分析
直接算方案数比较难办,转而计算序列数。
如果不考虑不合法的删除(变成不下降之后继续删),那么设长度为(i)的不下降子序列有(g_i)个,那么得到长度为(i)的子序列的方案数为(g_i(n-i)!) 。
现在我们求出所有不管不合法的(g_i),那么(g_i)中的不合法情况必定是从(g_{i+1})删除一个位置得到的,这是因为(g_{i+1})包含了(g_i)的直接不合法情况和间接不合法情况,因为它自己包含了后面的不合法情况。例子(a=(1,7,3,5))可以清楚地说明这一点。
[ans=sum g_i(n-i)!-g_{i+1}(n-i-1)!(i+1)
]
(g_i)如何求呢?退而求其次,我们算(f[i][j]),表示长度为(i)以(j)结尾的子序列数量。
[egin{aligned}
f[i][j]=sum f[i-1][k] && k<j,a_kle a_j
end{aligned}
]
离散化(a),用树状数组可以优化到(O(n^2log n))。
这题关键是首先要想到求序列数,接着就是通过减掉不合法情况来计算。
代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<numeric>
#include<algorithm>
using namespace std;
typedef long long giant;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=2e3+1;
const int q=1e9+7;
inline int Plus(int x,int y) {return ((giant)x+(giant)y)%q;}
inline int Multi(int x,int y) {return (giant)x*y%q;}
inline int Sub(int x,int y) {return Plus(x,q-y);}
int a[maxn],b[maxn],c[maxn],fac[maxn],n,f[maxn][maxn],g[maxn];
inline int lowbit(int x) {return x&-x;}
inline void inc(int x,int d) {for (;x<=n;x+=lowbit(x)) c[x]=Plus(c[x],d);}
inline int sum(int x) {
int ret=0;
for (;x;x-=lowbit(x)) ret=Plus(ret,c[x]);
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
n=read();
fac[0]=1;
for (int i=1;i<=n;++i) fac[i]=Multi(fac[i-1],i);
for (int i=1;i<=n;++i) a[i]=b[i]=read();
sort(b+1,b+n+1);
int 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;
for (int i=1;i<=n;++i) f[1][i]=1;
for (int i=2;i<=n;++i) {
memset(c,0,sizeof c);
for (int j=1;j<=n;++j) {
f[i][j]=Plus(f[i][j],sum(a[j]));
inc(a[j],f[i-1][j]);
}
}
for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) g[i]=Plus(g[i],f[i][j]);
int ans=0;
for (int i=n;i;--i) ans=Plus(ans,Sub(Multi(g[i],fac[n-i]),Multi(Multi(g[i+1],fac[n-i-1]),i+1)));
printf("%d
",ans);
return 0;
}