ZR#1015

ZR#1015

解法:

我们需要求得, $ g_i $ 表示长度为的最长不下降子序列个数。
设 $ f_{i,j} $ 表示统计第前$ i $ 个数字,得到最长不下降子序列末端为 $ j $ 。
显然这个状态可以从前面所有转移过来。
树状数组优化一下。
考虑到在 $ g_i $ 状态下,我们可以以任意顺序删去个 $ n-i $ 数,则长度为 $ i $ 的最长不下降子序列方案数为 $ g_i(n - i) !$
但是,不能保证它在成为最长不下降子序列时就停止删数。
不合法方案数为 $ g_{i+1}
(n- i - 1)! * (i + 1) $ (最后一次可以删个数中任意一个)。
所以统计答案的时候就是 $ ans = g_i * (n - i)! - g_{i+1}*(n-i-1)! * (i + 1) $

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;

#define LL long long
#define N 2010
const int mod = 1e9 + 7;

int n,pos[N];
LL a[N],t[N],sum[N][N];
LL f[N][N],g[N],fac[N],ans;

inline int lowbit(int x) {
    return x & -x;
}
void update(int id,int x,LL v) {
    for(int i = x ; i <= n ; i += lowbit(i))
        sum[id][i] = (sum[id][i] + v) % mod;
}
LL query(int id,int x) {
    LL ans = 0;
    for(int i = x ; i ; i -= lowbit(i))
        ans = (ans + sum[id][i]) % mod;
    return ans;
}

int main() {
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i++)
        scanf("%lld",&a[i]);
    for(int i = 1 ; i <= n ; i++) t[i] = a[i];
    sort(t + 1,t + n + 1);
    int num = unique(t + 1,t + n + 1) - t - 1;
    fac[1] = 1;
    for(int i = 1 ; i <= n ; i++) 
        pos[i] = lower_bound(t + 1,t + num + 1,a[i]) - t;
    for(int i = 2 ; i <= n ; i++)
        fac[i] = 1LL * fac[i - 1] * i % mod;
    update(0,1,1);
    for(int i = 1 ; i <= n ; i++) {
        for(int j = i ; j >= 1 ; j--) {
            f[i][j] = (f[i][j] + query(j - 1,pos[i]) % mod) % mod;
            update(j,pos[i],f[i][j] % mod);
        }
    }
    for(int i = 1 ; i <= n ; i++) {
        for(int j = 1 ; j <= n ; j++) {
            g[i] = (g[i] + f[j][i]) % mod;
        }
    }
    for(int i = 1 ; i <= n ; i++)
        ans = ((ans % mod + (fac[n - i] % mod * g[i] % mod) % mod) % mod - fac[n - i - 1] % mod * g[i + 1] % mod * (i + 1) % mod + mod) % mod;
    printf("%lld\n",ans);
    //system("pause");
    return 0;
}
posted @ 2019-10-20 20:19  西窗夜雨  阅读(149)  评论(0编辑  收藏  举报