[BZOJ4361] isn

[BZOJ4361] isn

Description

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

Input

第一行一个整数n。接下来一行n个整数,描述A。

Output

一行一个整数,描述答案。

Sample Input

4
1 7 5 3

Sample Output

18

HINT

1<=N<=2000

试题分析

首先这个问题肯定需要整体考虑,所以只能先求出\(g_i\)为长度为i的非将子序列数量。
那么我们来思考去重,发现一种情况合法当且仅当一直存在一个\(a_j<a_i\space (j>i)\),那么如果我们想保留最后的指定序列,一定存在\(a_j<a_{b_i}\space (j>b_i)\)
那么可以得到一个simple的dp:\(f_{i,j,k}\)表示考虑到\(i\),非降序列最后一个是\(j\),一共有\(k\)个上面的数对的方案数。
但是这样是妥妥的MLE+TLE。。。
考虑单独状态(dp)不行就考虑状态之间的关系(容斥):\(g_i\)不合法一定是从\(g_{i+1}\)删掉一个得到。
所以有:$$ans=\sum g_i(n-i)!-g_{i+1}(n-i-1)!(i+1)$$

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
 
using namespace std;
#define LL long long
 
inline LL read(){
    LL 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 LL INF = 2147483600;
const LL MAXN = 3000;
const LL Mod = 1e9+7;
 
LL N; LL a[MAXN+1],b[MAXN+1];
LL c[2010],s[MAXN+1];
LL f[MAXN+1][MAXN+1];
LL g[MAXN+1],ans;
 
inline LL lowbit(LL x){return x&(-x);}
inline void Add(LL i,LL k){
    for(LL x=i;x<=N;x+=lowbit(x)){
            c[x]+=k; if(c[x]>=Mod) c[x]-=Mod;
    } return ;
}
inline LL Query(LL i){
    LL res=0; if(!i) return 1;
    for(LL x=i;x;x-=lowbit(x)){
            res+=c[x]; if(res>=Mod) res-=Mod;
    }
    return res;
}
 
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    N=read(); s[0]=1LL;
    for(LL i=1;i<=N;i++) s[i]=s[i-1]*i%Mod;
    for(LL i=1;i<=N;i++) b[i]=a[i]=read();
    sort(b+1,b+N+1);
    for(LL i=1;i<=N;i++) a[i]=lower_bound(b+1,b+N+1,a[i])-b;
    for(LL i=1;i<=N;i++) f[1][i]=1;
    for(LL i=2;i<=N;i++){
        memset(c,0,sizeof(c));
        for(LL j=1;j<=N;j++){
            f[i][j]+=Query(a[j]);
            if(f[i][j]>=Mod) f[i][j]-=Mod;
            Add(a[j],f[i-1][j]);
        }
    }
    for(LL i=1;i<=N;i++) for(LL j=1;j<=N;j++) g[i]+=f[i][j],g[i]=(g[i]>=Mod?g[i]-Mod:g[i]);
    for(LL i=1;i<=N;i++) ans+=(g[i]*s[N-i]%Mod-g[i+1]*s[N-i-1]%Mod*(i+1)%Mod+Mod)%Mod,ans=(ans>=Mod?ans-Mod:ans);
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-08-24 22:11  wxjor  阅读(151)  评论(0编辑  收藏  举报