P3600 随机数生成器

首先转化为求 \(\displaystyle \sum_{k\ge 1}P( \max_{i} \{ \min_{l_i \le j \le r_i}a_j \} \ge k)\)

注意到右端点同为 \(i\) 的区间只有左端点最大的区间贡献答案,记其左端点为 \(l_i\)

方向1. 直接计算

\(p\) 表示填一个 \(\ge k\) 的数的概率,

\(f_{i,j}\) 表示前 \(i\) 个数,连续 \(j\) 个数的值 \(\ge k\) 的概率,有

\[f_{i,j}=\begin{cases} (1-p)\sum_{l=0}^{i-1}f_{i-1,l} & j=0 \\ p f_{i-1,j-1} & j \not= 0 \end{cases}\]

\(l_i \ge i-j+1\) 时贡献答案并将 \(f_{i,j}\)\(0\)

复杂度 \(\mathcal O(n^3)\)

方向2. 反向计算

注意到 \(\max \ge k\) 并不好计算,我们计算其补集 \(\max < k\),也就是每个区间的 \(\min<k\)

\(f_{i,j}\) 表示前 \(i\) 个数,上一个 \(<k\) 的位置为 \(j\) 的概率,有

\[f_{i,j}=\begin{cases} 0 & j < l_i \\ pf_{i-1,j} & j \ge l_i ,j \not= i \\ (1-p)\sum_{l=0}^{i-1}f_{i-1,l} & j=i \end{cases}\]

此时的转移没有移位,也就是说 \(j \ge \max_{k \le i}l_k\)\(f\) 不为 \(0\)

那么维护 \(f\) 的和即可,复杂度 \(\mathcal O(n^2)\)

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2000 , Mod = 666623333;
inline int Add( int x , int y ) { x += y; return x >= Mod ? x - Mod : x; }
inline int Sub( int x , int y ) { x -= y; return x < 0 ? x + Mod : x; }
inline int Mul( int x , int y ) { return 1ll * x * y % Mod; }
inline int Qkpow( int x , int po ) { int p = 1; for( ; po ; po >>= 1 , x = Mul( x , x ) ) if( po & 1 ) p = Mul( p , x ); return p; }
inline int Inv( int x ) { return Qkpow( x , Mod - 2 ); }

int n , m , q , l[ MAXN + 5 ];
int pw[ MAXN + 5 ] , f[ MAXN + 5 ];

int main( ) {
    scanf("%d %d %d",&n,&m,&q);
    for( int i = 1 , ql , qr ; i <= q ; i ++ ) {
        scanf("%d %d",&ql,&qr);
        l[ qr ] = max( l[ qr ] , ql );
    }

    int ans = 0;
    for( int k = 1 ; k <= m ; k ++ ) {
        int p = Mul( m - k + 1 , Inv( m ) );
        pw[ 0 ] = 1;
        for( int i = 1 ; i <= n ; i ++ ) pw[ i ] = Mul( pw[ i - 1 ] , p );

        f[ 0 ] = 1; int sf = 1;
        for( int i = 1 , mxl = -1 ; i <= n ; i ++ ) {
            f[ i ] = Mul( Sub( 1 , p ) , sf );
            for( int j = mxl + 1 ; j < l[ i ] ; j ++ ) sf = Sub( sf , Mul( f[ j ] , pw[ i - j ] ) ); 
            mxl = max( mxl , l[ i ] - 1 );
        }
        ans = Add( ans , Sub( 1 , sf ) );
    }
    printf("%d\n", ans );
    return 0;
}
posted @ 2022-10-07 21:31  chihik  阅读(31)  评论(0编辑  收藏  举报