「Gym102979E」Expected Distance

题目

点这里看题目。

分析

对答案变形:

[sum_{ein P}c_{e_u}+c_{e_v}=2sum_{win P,w ot=u,w ot= v}c_w+c_u+c_v ]

因此我们需要关心的是最终路径上非 (u) 且非 (v) 的点的点权和。

假设 (u<v),我们先画一条路径来分析一下:

graph.png

考虑路径出现的概率,对于任何一条边 ((p,q),p<q),设 (s_n=sum_{i=1}^na_i),则该边出现的概率为 (frac{a_p}{s_{q-1}})。每条边的概率之积则为该路径出现的概率。而我们可以重新排列,使得各个点贡献独立。比如上面这条路径,(u,v) 分别贡献 (s^{-1}_{u-1},s_{v-1}^{-1})(lca) 会贡献 (a^2_{lca}),而路径上的点 (win {a,b,c,d,e}) 则会贡献 (frac{a_w}{s_{w-1}})

所以,当我们确定了 (u,v,lca) 之后,剩余的点可出现可不出现,系数易于计算。因此自然的思路是尝试枚举 (Psetminus{u,v,lca}),反向构造出路径来。

在此之前,我们需要明确当路径以 (lca) 为根的时候,路径在标号上满足堆性质。因此假如我们知道了 (u)(lca) 上的点和 (v)(lca) 上的点,则两条链上点的顺序是确定的。那么对于 (win Psetminus {u,v,lca}),如果有 (w<u),则在反向构建的时候,(w) 既可以被放入 (u) 链,也可以被放入 (v) 链,贡献 2 的系数;而如果 (u<w<v),则 (w) 不能被放入 (u) 链,只能被放入 (v) 链,贡献 1 的系数。

此外,注意到概率是乘法的关系,而最终的点权需要求和,自然的想法便是将点权放到指数上,使用概率生成函数。

因此,对于路径 ((u,v)),我们可以构建 (F_k(x))(lca=k) 时该路径的点权的概率生成函数,根据上面的分析不难得出:

[egin{aligned} F_u(x)&=frac{a_u}{s_{v-1}}prod_{u<j<v}left(1+frac{a_j}{s_{j-1}}x^{c_j} ight)\ F_k(x)&=frac{a_k^2x^{c_k}}{s_{u-1}s_{v-1}}prod_{k<j<u}left(1+frac{2a_j}{s_{j-1}}x^{c_j} ight)prod_{u<j<v}left(1+frac{a_j}{s_{j-1}}x^{c_j} ight),1le k<u end{aligned} ]

根据结论,计算出 (sum_{1le kle u}F_k'(1)) 就是答案,使用若干个前缀数组记录一下即可。

计算量确实比较大,但是带入值的时候,由于 (c_jge 1),细节不多。

小结:

  1. 注意对问题下手的角度,这里是对链本身考虑,而另一种更简单的方法是将贡献拆分成 (dep_{u}+dep_{v}-2dep_{lca}) 的类似的形式,于是就转化到了祖先与子孙上。虽然这个做法比较复杂,但是我觉得挺漂亮的

  2. 注意细节,算错好多次导致浪费了不少时间,比如最开始的时候就没有意识到 2 的方案系数。这种题可以通过手玩关注到不少细节。

    另一方面,这其实也说明计数的思路不太完整,忽略了路径的点在分配时候带来的方案系数。这个其实随便画一画 (n=4) 都可以发现好嘛

代码

#include <cstdio>
#include <iostream>

#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )

const int mod = 1e9 + 7;
const int MAXN = 3e5 + 5;

template<typename _T>
void read( _T &x )
{
	x = 0; char s = getchar(); int f = 1;
	while( ! ( '0' <= s && s <= '9' ) ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) write( x / 10 );
	putchar( x % 10 + '0' );
}

int P[MAXN], Pder[MAXN];
int H[MAXN], Hder[MAXN];
int T[MAXN], TDer[MAXN];
int R[MAXN], RDer[MAXN];
int pre[MAXN], preDer1[MAXN], preDer2[MAXN];

int a[MAXN], s[MAXN], c[MAXN], invS[MAXN];
int N, Q;

inline int Qkpow( int, int );
inline int Mul( int x, int v ) { return 1ll * x * v % mod; }
inline int Inv( const int a ) { return Qkpow( a, mod - 2 ); }
inline int Sub( int x, int v ) { return ( x -= v ) < 0 ? x + mod : x; }
inline int Add( int x, int v ) { return ( x += v ) >= mod ? x - mod : x; }

inline int Sqr( const int x ) { return Mul( x, x ); }

inline int Qkpow( int base, int indx )
{
	int ret = 1;
	while( indx )
	{
		if( indx & 1 ) ret = Mul( ret, base );
		base = Mul( base, base ), indx >>= 1;
	}
	return ret;
}

int main()
{
	read( N ), read( Q );
	rep( i, 1, N - 1 ) read( a[i] );
	rep( i, 1, N ) read( c[i] );
	rep( i, 1, N ) invS[i] = Inv( s[i] = Add( s[i - 1], a[i] ) );
	R[0] = H[0] = 1;
	rep( i, 1, N )
	{
		T[i] = Add( 1, Mul( a[i], invS[i - 1] ) );
		TDer[i] = Mul( Mul( a[i], c[i] ), invS[i - 1] );
		R[i] = Mul( R[i - 1], T[i] );
		RDer[i] = Add( Mul( RDer[i - 1], T[i] ), Mul( R[i - 1], TDer[i] ) );
		
		P[i] = Add( 1, Mul( Mul( 2, a[i] ), invS[i - 1] ) );
		Pder[i] = Mul( Mul( Mul( 2, a[i] ), c[i] ), invS[i - 1] );
		H[i] = Mul( H[i - 1], P[i] );
		Hder[i] = Add( Mul( Hder[i - 1], P[i] ), Mul( H[i - 1], Pder[i] ) );
		
		int inv = Inv( H[i] );
		pre[i] = Add( pre[i - 1], Mul( inv, Sqr( a[i] ) ) );
		preDer1[i] = Add( preDer1[i - 1], Mul( Sqr( inv ), Mul( Hder[i], Sqr( a[i] ) ) ) );
		preDer2[i] = Add( preDer2[i - 1], Mul( inv, Mul( Sqr( a[i] ), c[i] ) ) );
	}
	while( Q -- )
	{
		int u, v;
		read( u ), read( v );
		if( u > v ) std :: swap( u, v );
		if( u == v ) { puts( "0" ); continue; }
		int ans = 0, res = 0, G;
		ans = Mul( Mul( a[u], invS[v - 1] ), Mul( Sqr( Inv( R[u] ) ), 
				   Sub( Mul( RDer[v - 1], R[u] ), Mul( R[v - 1], RDer[u] ) ) ) );
		G = Mul( Sqr( Inv( R[u] ) ), Sub( Add( Mul( Mul( Hder[u - 1], R[v - 1] ), R[u] ),
											   Mul( Mul( H[u - 1], RDer[v - 1] ), R[u] ) ), 
											   Mul( Mul( H[u - 1], R[v - 1] ), RDer[u] ) ) );
		res = Add( res, Mul( G, pre[u - 1] ) );
		G = Mul( Mul( H[u - 1], R[v - 1] ), Inv( R[u] ) );
		res = Add( res, Mul( G, Sub( preDer2[u - 1], preDer1[u - 1] ) ) );
		ans = Add( ans, Mul( res, Mul( invS[u - 1], invS[v - 1] ) ) );
		
		write( Add( Mul( ans, 2 ), Add( c[u], c[v] ) ) ), putchar( '
' );
	}
	return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/15205007.html