题目描述
小Yuuka遇到了一个题目:有一个序列a_1,a_2,…,a_n,q次操作,每次把一个区间内的数改成区间内的最大值,问最后每个数是多少。小Yuuka很快地就使用了线段树解决了这个问题。
于是充满智慧的小Yuuka想,如果操作是随机的,即在这q次操作中每次等概率随机地选择一个区间l,r,然后将这个区间内的数改成区间内最大值(注意这样的区间共有(n(n+1))/2(n(n+1))/2(n(n+1))/2个),最后每个数的期望大小是多少呢?小Yuuka非常热爱随机,所以她给出的输入序列也是随机的(随机方式见数据规模和约定)。对于每个数,输出它的期望乘((n(n+1))/2)q((n(n+1))/2)^q((n(n+1))/2)q再对109+710^9+7109+7取模的值。
输入输出格式
输入格式:
第一行包含2个正整数n,q,表示序列里数的个数和操作的个数。接下来1行,包含n个非负整数a1,a2…an。N<=400,Q<=400N<=400,Q<=400N<=400,Q<=400
输出格式:
输出共1行,包含n个整数,表示每个数的答案
输入输出样例
输入样例#1:
5 5
1 5 2 3 4
输出样例#1:
3152671 3796875 3692207 3623487 3515626
分析:
设f[x][i][l][r]f[x][i][l][r]f[x][i][l][r]表示过了iii轮,lll~rrr的数都小于等于xxx的答案。
显然对于每个a[i]a[i]a[i],他能影响到的范围从左边第一个比他大的数的右边到右边第一个比他大的数的左边。
考虑转移,第一种是原区间转移,即f[x][i−1][l][r]f[x][i-1][l][r]f[x][i−1][l][r]→f[x][i][l][r]f[x][i][l][r]f[x][i][l][r],显然此时的更新区间要不是[l,r][l,r][l,r]的自己子集,要不是根本与[l,r][l,r][l,r]没有任何交集。
所以,f[x][i][l][r]=f[x][i−1][l][r]∗s[l][r]f[x][i][l][r]=f[x][i-1][l][r]*s[l][r]f[x][i][l][r]=f[x][i−1][l][r]∗s[l][r]
其中,s[l][r]=(l−12)+(n−r2)+(r−l+12)s[l][r]=\binom{l-1}{2}+\binom{n-r}{2}+\binom{r-l+1}{2}s[l][r]=(2l−1)+(2n−r)+(2r−l+1)。
第二种转移是从f[x][i−1][l][k](k>r)f[x][i-1][l][k](k>r)f[x][i−1][l][k](k>r)和f[x][i−1][k][r](k<l)f[x][i-1][k][r](k<l)f[x][i−1][k][r](k<l)转移,显然只要区间是子集或者根本没有交集即可。
然后可以使用前缀和优化求出,即可得出区间内任何一个数变成<=x<=x<=x的方案,求解即可。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define LL long long
const int N=407;
const LL mod=1e9+7;
using namespace std;
int n,m,l,r;
int a[N],b[N],s[N][N];
LL f[2][N][N],g[N][N],t;
int calc(int n)
{
return n*(n+1)/2;
}
void solve(int l,int r,int d)
{
memset(f,0,sizeof(f));
int p=0;
f[p][l][r]=1;
for (int k=1;k<=m;k++)
{
p^=1;
for (int i=l;i<=r;i++)
{
t=0;
for (int j=r;j>=i;j--)
{
f[p][i][j]=t%mod;
t+=f[p^1][i][j]*(LL)(n-j);
}
}
for (int j=l;j<=r;j++)
{
t=0;
for (int i=l;i<=j;i++)
{
f[p][i][j]=(f[p][i][j]+t+f[p^1][i][j]*s[i][j])%mod;
t+=f[p^1][i][j]*(LL)(i-1);
}
}
}
for (int i=l;i<=r;i++)
{
t=0;
for (int j=r;j>=i;j--)
{
t+=f[p][i][j],g[j][a[d]]=(g[j][a[d]]+t)%mod;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1);
int sz=unique(b+1,b+n+1)-b-1;
for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+sz+1,a[i])-b;
for (int i=1;i<=n;i++)
{
for (int j=i;j<=n;j++) s[i][j]=calc(i-1)+calc(j-i+1)+calc(n-j);
}
for (int i=1;i<=n;i++)
{
l=r=i;
while ((l>1) && (a[l-1]<=a[i])) l--;
while ((r<n) && (a[r+1]<=a[i])) r++;
solve(l,r,i);
}
for (int i=1;i<=n;i++)
{
t=0;
for (int j=1;j<=n;j++)
{
if (!g[i][j]) g[i][j]=g[i][j-1];
t+=(g[i][j]-g[i][j-1])*b[j];
}
printf("%lld ",(t%mod+mod)%mod);
}
}