BZOJ4361 isn 【树状数组优化DP】*

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


我们可以设 dp[i][j] d p [ i ] [ j ] 是前i个数,选出包含i的j个数的方案数,然后我们发现转移其实很显然, dp[i][j]=dp[k][j1] d p [ i ] [ j ] = ∑ d p [ k ] [ j − 1 ] ,然后这玩意可以树状数组维护一下就优化下来了

然后贼优秀

#include
using namespace std;
#define LL long long
#define inf 0x3f3f3f3f
#define N 2010
#define yyf 1000000007
LL n,newn,a[N],b[N],J[N];
LL t[N][N],dp[N];
void add(LL &a,LL b){a=(a+b)%yyf;}
void add(LL k,LL pos,LL vl){for(;pos<=newn;pos+=pos&(-pos))add(t[k][pos],vl);}
LL query(LL k,LL pos){LL res=0;for(;pos;pos-=pos&(-pos))add(res,t[k][pos]);return res;}
int main(){
    scanf("%lld",&n);
    J[0]=1;for(LL i=1;i<=n;i++)J[i]=1ll*i*J[i-1]%yyf;
    for(LL i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    newn=unique(b+1,b+n+1)-b-1;
    for(LL i=1;i<=n;i++)a[i]=lower_bound(b+1,b+newn+1,a[i])-b;
    add(0,1,1);
    for(LL i=1;i<=n;i++)
        for(LL j=i;j>=1;j--){
            LL tmp=query(j-1,a[i]);
            add(dp[j],tmp);
            add(j,a[i],tmp);
        }
    LL ans=0;
    for(LL i=1;i<=n;i++){
        add(ans,J[n-i]*dp[i]%yyf);
        if(i!=n)add(ans,yyf-J[n-i-1]*(i+1)%yyf*dp[i+1]%yyf);
    }
    printf("%lld\n", ans);
    return 0;
}

你可能感兴趣的:(树状数组,DP,c++,BZOJ,DP,树状数组,DP,数据结构,好题)