题目大意
一个随机的序列长度为n。
有m次操作,每次随机选择一个区间[l,r],将这个区间所有数变成最大值。
问每个位置在m次操作后的期望。
答案模1e9+7
n<=400,权值随机
DP
权值随机的条件可以认为权值互不相同
离散化
我们设sum[i][j]表示第i个位置变成第j小的权值的方案数。
我们一个数一个数的做,设当前做的数是第now小,权值为val[now]。
我们设g[k,i,j]表示k次操作后一个极大区间[i,j]满足区间内每个数都不超过val[now],因为是极大所以如果存在位置i-1和j+1,一定有i-1和j+1位置上的权重比val[now]大。
我们思考怎么转移。
k次操作后极大区间是[i,j],那么k-1次操作时极大区间有几种可能:
1、是[u,j],
u<i
,那么我们肯定是选择了一个小于u的位置w,然后操作了[w,i-1],才会使得极大区间变成[i,j]。
2、是[i,v],基本同上。
3、就是[i,j],那么我们选择的操作区间要么被[i,j]包含,要么与[i,j]不相交。
就三种转移的情况,dp即可。
最后统计答案的时候,把<=j变成=j即可。注意dp数组为0的位置表示该情况不可能出现。
需要卡常,我卡过了UOJ没卡过bzoj。。
代码的很多实现其实是抄的QAQ
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define dp(i,j,k) dp[(i)%2][(j)][(k)]
using namespace std;
typedef long long ll;
const int maxn=400+10,mo=1000000007;
int L[maxn],R[maxn],a[maxn],b[maxn][maxn],rank[maxn];
ll dp[2][maxn][maxn],sum[maxn][maxn];
int sta[80],cnt[maxn],val[maxn];
int i,j,k,l,t,n,m,ans,top;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void solve(int l,int r,int now){
int i,j,k;
ll t;
fo(i,l,r)
fo(j,l,r)
dp(0,i,j)=dp(1,i,j)=0;
dp(0,l,r)=1;
fo(k,1,m){
fo(j,l,r){
t=0;
fo(i,l,j){
dp(k,i,j)=t;
t+=(ll)dp(k-1,i,j)*(i-1)%mo;
}
}
fo(i,l,r){
t=0;
fd(j,r,i){
(dp(k,i,j)+=t)%=mo;
t+=(ll)dp(k-1,i,j)*(n-j)%mo;
}
}
fo(i,l,r)
fo(j,i,r)
dp(k,i,j)=(dp(k,i,j)+dp(k-1,i,j)*b[i][j]%mo)%mo;
}
fo(i,l,r){
t=0;
fd(j,r,i){
t+=dp(m,i,j);
(sum[j][rank[now]]+=t)%=mo;
}
}
}
void write(int x){
if (!x){
putchar('0');
//putchar(' ');
return;
}
top=0;
while (x){
sta[++top]=x%10;
x/=10;
}
while (top) putchar('0'+sta[top--]);
//putchar(' ');
}
int main(){
//freopen("data.in","r",stdin);
n=read();m=read();
fo(i,0,n) cnt[i]=i*(i+1)/2;
fo(i,1,n)
fo(j,i,n)
b[i][j]=((ll)cnt[i-1]+(ll)cnt[n-j]+(ll)cnt[j-i+1])%mo;
fo(i,1,n) a[i]=read(),val[i]=a[i];
sort(val+1,val+n+1);
fo(i,1,n) rank[i]=a[i]=lower_bound(val+1,val+n+1,a[i])-val;
fo(i,1,n){
j=i-1;
while (j&&a[j]<=a[i]) j=L[j]-1;
L[i]=j+1;
}
fd(i,n,1){
j=i+1;
while (j<=n&&a[j]<=a[i]) j=R[j]+1;
R[i]=j-1;
}
fo(i,1,n) solve(L[i],R[i],i);
fo(i,1,n){
ans=0;t=0;
fo(j,1,n){
if (!sum[i][j]) continue;
sum[i][j]=(sum[i][j]-t)%mo;
t=(t+sum[i][j])%mo;
ans=(ans+(ll)sum[i][j]*val[j]%mo)%mo;
}
(ans+=mo)%=mo;
write(ans);
if (i<n) putchar(' ');
}
}