[ZJOI2016]线段树
给定 (n) 个数 (a_{1,2...n}),每次随机操作一个区间,即将这个区间 ([l,r]) 的数变成这个区间的 (max)
操作 (Q) 次,输出最后每个元素的权值的期望。
(n,Qle 400)
Solution
期望的套路是差分贡献,当然直接计数也可以这样处理,所以不妨枚举 (x),设 (f_{l,r,k}) 表示当前操作了 (k) 次,区间 ([l,r]) 均小于 (x),同时 (a_{l-1},a_{r+1}) 均大于等于 (x) 的方案数。(当然小于等于的位置设为 (0),其他位置设为 (1)),那么答案即为 (max - sum f_{...} imes (w_x-w_{x-1}))
然后考虑转移:
[f_{l,r,k}=f_{l,r,k-1} imes q(l,r)+sum_{j< l} f_{j,r,k-1}(j-1)+sum_{j> r}f_{l,j,k-1}(n-j)
]
其中 (q(l,r)) 表示无用操作的数量。
考虑前缀和数组 (S_1(l,r,k),S_2(l,r,k)),分别维护一下即可,复杂度为 (mathcal O(n^3q))
可以考虑将初始值设为 (w_x-w_{x-1}),这样就不需要将答案乘以 (w_x) 了。
考虑优化到 (mathcal O(n^3)),不难发现对于不同的 (x),转移只有初值不同,所以对每个区间预处理初值和即可。
注意到 ([l,r]) 的初值即 (min(a_{l-1},a_{r+1})-max(a_{l,l+1...r})),于是复杂度 (mathcal O(n^2q))
(Code:)
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define F(x) ((x) * (x + 1) / 2)
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int N = 400 + 5 ;
const int P = 1e9 + 7 ;
int n, q, a[N], mx[N][N], f[N][N][2], S1[N][N], S2[N][N] ;
int w(int l, int r) {
return F(l - 1) + F(n - r) + F(r - l + 1) ;
}
signed main()
{
n = gi(), q = gi() ;
rep( i, 1, n ) a[i] = gi() ;
int mi = a[1] ;
rep( i, 1, n ) mi = min( mi, a[i] ) ;
rep( l, 1, n ) rep( r, l, n ) mx[l][r] = max( mx[l][r - 1], a[r] ) ;
rep( l, 1, n ) rep( r, l, n ) {
if( min( a[l - 1], a[r + 1] ) > mx[l][r] )
f[l][r][0] = min( a[l - 1], a[r + 1] ) - mx[l][r] ;
if( l == 1 && a[r + 1] > mx[l][r] )
f[l][r][0] = a[r + 1] - mx[l][r] ;
if( r == n && a[l - 1] > mx[l][r] )
f[l][r][0] = a[l - 1] - mx[l][r] ;
}
f[1][n][0] = 0 ;
rep( r, 1, n ) rep( l, 1, r ) S1[l][r] = (S1[l - 1][r] + f[l][r][0] * (l - 1) ) % P ;
rep( l, 1, n ) drep( r, l, n ) S2[l][r] = (S2[l][r + 1] + f[l][r][0] * (n - r) ) % P ;
rep( u, 1, q ) {
int k = u & 1 ;
rep( l, 1, n ) rep( r, l, n )
f[l][r][k] = (f[l][r][k ^ 1] * w(l, r) % P + S1[l - 1][r] + S2[l][r + 1] ) % P ;
rep( r, 1, n ) rep( l, 1, r ) S1[l][r] = (S1[l - 1][r] + f[l][r][k] * (l - 1) ) % P ;
rep( l, 1, n ) drep( r, l, n ) S2[l][r] = (S2[l][r + 1] + f[l][r][k] * (n - r) ) % P ;
}
int p = n * (n + 1) / 2, D = 1 ;
rep( i, 1, q ) D = D * p % P ; q = q & 1 ;
rep( i, 1, n ) {
int ans = mx[1][n] * D % P ;
rep( l, 1, n ) rep( r, l, n ) if( l <= i && i <= r ) ans = (ans - f[l][r][q] + P) % P ;
printf("%lld ", ans ) ;
}
return 0 ;
}