bzoj4574: [Zjoi2016]线段树

爆了一天。。。我还是太菜

ORZ

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'&&ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void write(LL x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>=10)write(x/10);
    putchar(x%10+'0');
}

int n,m;
int a[410],lslen,ls[410],L[410],R[410];
LL f[2][410][410];//什么时间,区间之中的点都以当前权值为最大值方案数 
LL g[410][410];//第i个位置变成了以排名<=j的权值为最大值的方案数 
LL FF[410],c[410][410];
void DP(int p)
{
    int now=0; LL s;
    memset(f,0,sizeof(f));f[now][L[p]][R[p]]=1;
    for(int k=1;k<=m;k++)
    {
        now^=1;
        for(int i=L[p];i<=R[p];i++)
        {
            s=0;
            for(int j=R[p];j>=i;j--)
                f[now][i][j]=s, s+=f[now^1][i][j]*(n-j);
        }
        for(int j=L[p];j<=R[p];j++)
        {
            s=0;
            for(int i=L[p];i<=j;i++)
                f[now][i][j]+=s, s+=f[now^1][i][j]*(i-1);
        }
        for(int i=L[p];i<=R[p];i++)
            for(int j=i;j<=R[p];j++)
                f[now][i][j]+=f[now^1][i][j]*c[i][j], f[now][i][j]%=mod;
    }
    
    for(int i=L[p];i<=R[p];i++) 
    {
        s=0;
        for(int j=R[p];j>=i;j--)
            s+=f[now][i][j], g[j][a[p]]=(g[j][a[p]]+s)%mod;
    }
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    n=read(),m=read(); lslen=0;
    for(int i=1;i<=n;i++)
        a[i]=read(),ls[++lslen]=a[i];
    sort(ls+1,ls+lslen+1);
    lslen=unique(ls+1,ls+lslen+1)-ls-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(ls+1,ls+lslen+1,a[i])-ls;
        
    for(int i=1;i<=n;i++)FF[i]=(i*i+i)/2;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            c[i][j]=FF[i-1]+FF[n-j]+FF[j-i+1];
    for(int i=1;i<=n;i++)
    {
        L[i]=1;for(int j=i-1;j>=1;j--)if(a[i]<a[j]){L[i]=j+1;break;}
        R[i]=n;for(int j=i+1;j<=n;j++)if(a[i]<a[j]){R[i]=j-1;break;}
        DP(i);
    }
    
    LL ans;
    for(int i=1;i<=n;i++)
    {
        ans=0;
        for(int j=1;j<=lslen;j++)
        {
            if(g[i][j]==0)continue;
            for(int k=1;k<j;k++)g[i][j]-=g[i][k];
            while(g[i][j]<0)g[i][j]+=mod;
            ans+=ls[j]*g[i][j],ans%=mod;
        }
        write(ans),putchar(' ');
    }
    //容斥 
    return 0;
}

 

posted @ 2018-12-30 17:06  AKCqhzdy  阅读(125)  评论(0编辑  收藏