[ZJOI2016] 线段树
先考虑
如果
如果
我们对初始每一个
这个柿子显然可以使用前缀和优化,每一次 dp 的复杂度就是
考虑一般序列怎么做。注意到最终序列的某个数
我们枚举这个
可以注意到
但其实我们可以找出稳定
关于为什么不拆为
时间复杂度
参考代码:
#include<bits/stdc++.h>
using namespace std;
#define N 405
#define MOD 1000000007
int n,m,ans[N],dp[N][N],s1[N][N],s2[N][N];bool vs[N];struct Node {int id,w;}a[N];
bool cmp(Node x,Node y) {return x.w<y.w;}
int add(int x,int y) {x+=y;return x<MOD?x:x-MOD;}
void W(int &x,int y) {x+=y;if(x>=MOD) x-=MOD;}
int qPow(int x,int y)
{int res=1;for(;y;y/=2,x=1ll*x*x%MOD) if(y&1) res=1ll*res*x%MOD;return res;}
int f(int l,int r) {return (l*(l+1)+(n-r+1)*(n-r+2)+(r-l-1)*(r-l))/2;}
int main()
{
scanf("%d %d",&n,&m);vs[n+1]=1;
for(int i=1;i<=n;++i) scanf("%d",&a[i].w),a[i].id=i;sort(a+1,a+n+1,cmp);
for(int i=n,lst;i;--i)
{
lst=0;vs[a[i].id]=1;
for(int j=1;j<=n+1;++j) if(vs[j]) dp[lst][j]+=a[i].w-a[i-1].w,lst=j;
}ans[1]=1ll*a[n].w*qPow(n*(n+1)/2,m)%MOD;for(int i=2;i<=n;++i) ans[i]=ans[1];
for(int i=1;i<=m;++i)
{
for(int j=0;j<=n;++j) for(int k=n+1;k>j+1;--k)
{
s1[j][k]=add(j?s1[j-1][k]:0,1ll*dp[j][k]*j%MOD);
s2[j][k]=add(k<=n?s2[j][k+1]:0,1ll*dp[j][k]*(n-k+1)%MOD);
}
for(int j=0;j<=n;++j) for(int k=j+2;k<=n+1;++k)
{
dp[j][k]=1ll*dp[j][k]*f(j,k)%MOD;
if(j) W(dp[j][k],s1[j-1][k]);if(k<=n) W(dp[j][k],s2[j][k+1]);
}
}for(int i=0;i<=n;++i) for(int j=i+2;j<=n+1;++j)
for(int k=i+1;k<j;++k) W(ans[k],MOD-dp[i][j]);
for(int i=1;i<=n;++i) printf("%d ",ans[i]);return 0;
}