Description
Solution
考虑将恰好转化为至少,即两两距离不小于z的概率,这是一个函数
f
(
z
)
f(z)
f ( z ) ,之后只要对
f
(
z
)
f(z)
f ( z ) 进行积分之后恰好就是答案了。 对于一个固定的
z
z
z ,我们可以将模型转换一下,第
i
i
i 个人对应的区间变为
[
x
i
−
1
−
(
i
−
1
)
z
,
x
i
−
(
i
−
1
)
z
]
[x_{i-1}-(i-1)z,x_i-(i-1)z]
[ x i − 1 − ( i − 1 ) z , x i − ( i − 1 ) z ] ,那么两两之间距离不超过
z
z
z 等价于在这个新的区间随机,最后
n
n
n 个人单调递增。 将这些区间没有用的部分除去,然后可以通过一个简单的DP求出期望函数,即设
F
[
i
]
[
j
]
F[i][j]
F [ i ] [ j ] 表示到了第
i
i
i 个端点,前面已经有
1
1
1 到
j
j
j 完成,枚举当前区间出现
j
+
1
j+1
j + 1 到
k
k
k ,里面是一个
n
n
n 次的多项式。转移可以做到
n
4
n^4
n 4 。 然后预处理
n
2
n^2
n 2 个节点大小关系交替的时刻,看作分段函数,对于每一段分别DP,分别积分即可。
O
(
n
6
)
O(n^6)
O ( n 6 )
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define maxn 22
#define db double
#define ll long long
#define mo 998244353
using namespace std;
int n, i, j, k, x[ maxn] , L[ maxn] , R[ maxn] , tot, p[ maxn* 2 ] , l[ maxn] , r[ maxn] , id0[ maxn* 2 ] , id1[ maxn* 2 ] ;
struct arr{ int x, y; ll p, q; } a[ maxn* maxn* 4 ] ;
int cmp ( arr a, arr b) { return a. p* b. q< b. p* a. q; }
ll ans, f[ maxn] [ maxn] , g[ maxn] , invf[ maxn] ;
ll ksm ( ll x, ll y) {
ll s= 1 ;
for ( ; y; y/ = 2 , x= x* x% mo) if ( y& 1 )
s= s* x% mo;
return s;
}
int X ( int x) { return ( x> n) ? R[ x- n] : L[ x] ; }
int I ( int x) { return ( x> n) ? x- n: x; }
int main ( ) {
freopen ( "ceshi.in" , "r" , stdin ) ;
scanf ( "%d" , & n) ;
invf[ 0 ] = 1 ; for ( i= 1 ; i<= n; i++ ) invf[ i] = invf[ i- 1 ] * ksm ( i, mo- 2 ) % mo;
for ( i= 0 ; i<= n; i++ ) scanf ( "%d" , & x[ i] ) ;
for ( i= 1 ; i<= n; i++ ) L[ i] = x[ i- 1 ] , R[ i] = x[ i] ;
for ( i= 1 ; i<= n; i++ ) for ( j= 1 ; j< i; j++ ) for ( int t1= 0 ; t1< 2 ; t1++ ) for ( int t2= 0 ; t2< 2 ; t2++ )
tot++ , a[ tot] . x= j+ t1* n, a[ tot] . y= i+ t2* n, a[ tot] . p= ( t2? R[ i] : L[ i] ) - ( t1? R[ j] : L[ j] ) , a[ tot] . q= i- j;
sort ( a+ 1 , a+ 1 + tot, cmp) ;
for ( i= 1 ; i<= n; i++ ) p[ ++ p[ 0 ] ] = i, p[ ++ p[ 0 ] ] = i+ n;
for ( int now= 1 ; now< tot; now++ ) {
int Tp= 0 ;
for ( i= 1 ; i<= n* 2 ; i++ ) if ( p[ i] == a[ now] . y) {
for ( j= i+ 1 ; j<= n* 2 ; j++ ) if ( p[ j] == a[ now] . x) Tp= 1 ;
if ( Tp) break ;
for ( j= i; j< n* 2 ; j++ ) p[ j] = p[ j+ 1 ] ;
break ;
}
if ( ! Tp)
for ( i= 1 ; i< n* 2 ; i++ ) if ( p[ i] == a[ now] . x) {
for ( j= n* 2 ; j> i; j-- ) p[ j] = p[ j- 1 ] ;
p[ i] = a[ now] . y; break ;
}
if ( a[ now] . p* a[ now+ 1 ] . q== a[ now+ 1 ] . p* a[ now] . q) continue ;
for ( i= 1 ; i<= n* 2 ; i++ ) if ( p[ i] <= n) l[ p[ i] ] = i; else r[ p[ i] - n] = i;
for ( i= 2 ; i<= n; i++ ) l[ i] = max ( l[ i] , l[ i- 1 ] ) ;
for ( i= n- 1 ; i>= 1 ; i-- ) r[ i] = min ( r[ i] , r[ i+ 1 ] ) ;
int tp= 1 ;
for ( i= 1 ; i<= n; i++ ) if ( l[ i] >= r[ i] ) { tp= 0 ; break ; }
if ( ! tp) break ;
memset ( id0, 0 , sizeof ( id0) ) , memset ( id1, 0 , sizeof ( id1) ) ;
for ( i= 1 ; i<= n; i++ ) id0[ l[ i] ] = max ( id0[ l[ i] ] , i) , id1[ r[ i] ] = max ( id1[ r[ i] ] , i) ;
memset ( f, 0 , sizeof ( f) ) , f[ 0 ] [ 0 ] = 1 ;
int st= 1 , ed= 0 ;
for ( i= 1 ; i< 2 * n; i++ ) {
ed= max ( ed, id0[ i] ) , st= max ( st, id1[ i] + 1 ) ;
if ( ed< st) continue ;
for ( j= ed- 1 ; j>= st- 1 ; j-- ) {
memcpy ( g, f[ j] , sizeof ( g) ) ;
ll v= X ( p[ i+ 1 ] ) - X ( p[ i] ) , u= - ( I ( p[ i+ 1 ] ) - I ( p[ i] ) ) ;
for ( k= 1 ; k<= ed- j; k++ ) {
for ( int t= j+ k; t; t-- )
g[ t] = ( g[ t] * v+ g[ t- 1 ] * u) % mo;
g[ 0 ] = g[ 0 ] * v% mo;
for ( int t= 0 ; t<= j+ k; t++ )
( f[ j+ k] [ t] + = g[ t] * invf[ k] ) % = mo;
}
}
}
ll X= a[ now] . p* ksm ( a[ now] . q, mo- 2 ) % mo;
ll Y= a[ now+ 1 ] . p* ksm ( a[ now+ 1 ] . q, mo- 2 ) % mo;
for ( i= 0 ; i<= n; i++ )
ans+ = f[ n] [ i] * ksm ( i+ 1 , mo- 2 ) % mo* ( ksm ( Y, i+ 1 ) - ksm ( X, i+ 1 ) ) % mo;
ans% = mo;
}
for ( i= 1 ; i<= n; i++ ) ans= ans* ksm ( x[ i] - x[ i- 1 ] , mo- 2 ) % mo;
printf ( "%lld\n" , ( ans% mo+ mo) % mo) ;
}