要点:一个不合法的状态一定是由一个长度多1的不下降子序列转移来的,直接减掉即可。
然后就转化为求长度为i的不下降子序列个数。定义f[i,j]表示以i结尾的,长度为j的不下降子序列个数,则f[i,j] = sum(f[k,j-1]), k<i&&a[k]<=a[i]。直接转移是n三方的,可以离散化后用树状数组维护前缀和。注意由于i这一维在树状数组中被省去了,枚举j需要倒着枚举防止被自己更新。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
#define LL long long
using namespace std;
const int inf = 0x3f3f3f3f, MAXN = 2005;
const int mo = 1000000007;
inline void add(int&a, const int&b) { a+=b; if(a>=mo) a-=mo; }
int N, a[MAXN], dat[MAXN], dn;
int jc[MAXN] = {1};
int f[MAXN][MAXN];
int bt[MAXN][MAXN]; // 长度i,值j
int idx(int x) { return lower_bound(dat+1, dat+dn+1, x) - dat; }
int h[MAXN];
void add(int k, int i, int x)
{
for (; i<=dn; i+=i&-i)
add(bt[k][i], x);
}
int qsum(int k, int i)
{
int r = 0;
for (; i>0; i-=i&-i)
add(r, bt[k][i]);
return r;
}
int main()
{
scanf("%d", &N);
rep(i, 1, N) scanf("%d", a+i), dat[i] = a[i];
sort(dat+1, dat+N+1);
dn = unique(dat+1, dat+N+1) - dat-1;
rep(i, 1, N) a[i] = idx(a[i]);
rep(i, 1, N) jc[i] = 1ll * i * jc[i-1] % mo;
add(0, 1, 1); //0会使树状数组死循环
rep(i, 1, N) erp(j, i, 1) //j倒着循环防止被自己更新
{
f[i][j] = qsum(j-1, a[i]);
add(h[j], f[i][j]);
add(j, a[i], f[i][j]);
}
int ans = 0;
rep(i, 1, N)
{
add(ans, 1ll * jc[N-i] * h[i] % mo);
if (i != N) add(ans, mo - 1ll * jc[N-i-1] * (i+1) % mo * h[i+1] % mo);
}
printf("%d\n", ans);
return 0;
}