[ZJOI2016]线段树

[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 ;
}
原文地址:https://www.cnblogs.com/Soulist/p/13675016.html