[BZOJ4574][UOJ#196][Zjoi2016][区间DP][概率]线段树

ZJOI2016 DAY2 看不懂题解系列……
http://www.cnblogs.com/Dragon-Light/p/6475923.html

#include 
#include 
#include 
#define N 410
#define P 1000000007

using namespace std;

typedef long long ll;

int n,m;
int A[N],B[N],R[N];
ll cnt[N][N],sum[N][N];
ll f[2][N][N];

inline void rea(int &x){
    char c=getchar(); x=0;
    for(;c>'9'||c<'0';c=getchar());
    for(;c>='0'&&c<='9';x=x*10+c-'0',c=getchar());
}

inline bool cmp(const int &a,const int &b){
    return A[a]inline void solve(int l,int r,int x){
    for(int i=l;i<=r;i++)
        for(int j=l;j<=r;j++)
            f[0][i][j]=f[1][i][j]=0;
    f[0][l][r]=1;
    for(int k=1;k<=m;k++){
        for(int i=l;i<=r;i++){
            ll w=0;
            for(int j=r;j>=i;j--)
                f[k&1][i][j]=w,w+=f[(k&1)^1][i][j]*(n-j);
        }

        for(ll j=l;j<=r;j++){
            ll w=0;
            for(int i=l;i<=j;i++)
                f[k&1][i][j]=(f[k&1][i][j]+w)%P,w+=f[(k&1)^1][i][j]*(i-1);
        }

        for(int i=l;i<=r;i++)
            for(int j=i;j<=r;j++)
                f[k&1][i][j]=(f[k&1][i][j]+f[(k&1)^1][i][j]*cnt[i][j])%P;
    }
    for(ll i=l;i<=r;i++){
        ll w=0;
        for(int j=r;j>=i;j--){
            w+=f[m&1][i][j];
            sum[j][R[x]]=(sum[j][R[x]]+w)%P;
        }
    }
}

inline int calc(int x){
    return x*(x+1)>>1;
}

int main(){
    rea(n); rea(m);
    for(int i=1;i<=n;i++) rea(A[i]),B[i]=i;
    sort(B+1,B+1+n,cmp);
    for(int i=1;i<=n;i++) R[B[i]]=i;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++) cnt[i][j]=calc(i-1)+calc(n-j)+calc(j-i+1);
    for(int i=1;i<=n;i++){
        int l=i,r=i;
        while(l&&A[i]>=A[l]) l--;
        while(r<=n&&A[i]>=A[r]) r++;
        solve(l+1,r-1,i);
    }
    for(int i=1;i<=n;i++){
        ll Ans=0;
        for(int j=1;j<=n;j++){
            //printf("%lld ",sum[i][j]);
            if(sum[i][j]==0) continue;
            for(int k=1;k1ll*A[B[j]]*sum[i][j])%P;
        }
        printf("%lld%c",Ans,i==n?'\n':' ');
    }
}

你可能感兴趣的:(DP,概率与期望,区间DP)