• ZJOI2020 抽卡


    第一次出现合法状态的期望时间可以转换为所有非法状态的出现概率乘以其在此处期望停留的时间。

    设此非法状态抽了 (r) 张卡,那么其有 (inom{m}{r}^{-1}) 的概率出现,经过 (frac{m}{m-r}) 时间后会到达下一个状态。

    只需要计数所有非法状态的数量即可。

    对每个极长连续段考虑,设其长度为 (n),考虑其中选出 (r) 张牌的方案数应为:

    [[x^{n+1-r}]igg(sum x^i[i<k]igg)^{r} ]

    这一部分基于这样的一个考虑,我们添加一个辅助元 (n+1) 并钦定其不被选中,这样的话我们枚举没有被选择的元素的个数,并为其前面添增 (0,1...k-1) 个被选中的元素,这样只需要将计算得到的答案反转系数即可得到选中了 (r) 个元素的方案数。

    因此,我们只需要考虑:

    [[x^{n+1-r}]igg(sum x^i[i<k]igg)^{r} ]

    接下来我们将结尾段的 (0) 加入计数的段落中,并添加辅助元 (u) 表示被选择的 (0) 的数量,设 (G(x)=sum_{ige 1}x^i[ile k]=xfrac{1-x^k}{1-x})

    则我们希望求解的就是:

    [sum (uG(x))^i=frac{1}{1-uG(x)}[x^{n+1}] ]

    (H(x)=frac{1}{1-ux}),则所求为 (H(G(x))[x^{n+1}]),设 (F(x))(G(x)) 的复合逆。

    我们直接上拓展拉格朗日反演:

    [frac{1}{1-uG(x)}[x^{n+1}]=frac{1}{n+1}frac{u}{(1-ux)^2}F(x)^{-(n+1)}[x^{-1}] ]

    也即:

    [frac{1}{n+1}frac{u}{(1-ux)^2}Big(frac{x}{F(x)}Big)^{(n+1)}[x^{n}] ]

    事实上,由于 (G(x)=frac{x-x^{k+1}}{1-x}),所以 (F(x)) 会满足:

    [frac{F(x)^{k+1}-F(x)}{F(x)-1}=x o F(x)^{k+1}-(1+x)F(x)+x=0 ]

    牛迭部分的方程如下:

    [F(x)=F_0(x)-frac{x^{k}F_0(x)^{k+1}-(1+x)F_0(x)+1}{x^{k}(k+1)F_0(x)^{k}-(1+x)} ]

    上面的 (F(x))(frac{F(x)}{x})

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define re register
    #define int long long
    #define vi vector<int>
    //视题目调节 
    const int P = 998244353 ; 
    const int Gi = 332748118 ;
    const int G = 3 ; 
    // 基本参数 
    const int N = 2e6 + 5 ; 
    int n, m, len, B[N], A[N], Dx[N] ; 
    vector<int> f[N] ; 
    int read() {
    	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' ) % P, cc = getchar() ;
    	return cn * flus ;
    }
    int fpow( int x, int k ) {
    	int ans = 1, base = x ;
    	while( k ) {
    		if( k & 1 ) ans = ans * base % P ; 
    		base = base * base % P, k >>= 1 ;
    	} return ans % P ; 
    }
    void inc(int &x, int y) {
    	((x += y) >= P) && (x -= P) ; 
    }
    void dec(int &x, int y) {
    	((x -= y) < 0) && (x += P) ; 
    }
    namespace Poly {
    	int limit, L, Inv, R[N], inv[N], gi[N << 1], igi[N << 1] ; 
    	void Init( int x ) {
    		limit = 1, L = 0 ; while( limit < x ) limit <<= 1, ++ L ;
    		rep( i, 0, limit ) R[i] = ( R[i >> 1] >> 1 ) | ( ( i & 1 ) << ( L - 1 ) ) ; 
    		Inv = fpow( limit, P - 2 ) ;
    	}
    	void _init( int x ) { // max x range
    		for( re int i = 0; i <= x; ++ i ) inv[i] = fpow( i, P - 2 ) ;
    		Init( x + x ) ; int num = 0 ;
    		for( re int k = 1; k < limit; k <<= 1 ) {
    			int d = fpow( G, ( P - 1 ) / ( k << 1 ) ) ;
    			for( re int j = 0, g = 1; j < k; ++ j, g = g * d % P ) gi[++ num] = g ;
    		} num = 0 ;
    		for( re int k = 1; k < limit; k <<= 1 ) {
    			int d = fpow( Gi, ( P - 1 ) / ( k << 1 ) ) ;
    			for( re int j = 0, g = 1; j < k; ++ j, g = g * d % P ) igi[++ num] = g ;
    		} 
    	}
    	void NTT( int *a, int type ) { //NTT多项式乘法 
    		for( re int i = 0; i < limit; ++ i ) if( i < R[i] ) swap( a[i], a[R[i]] ) ;
    		int num = 0 ;
    		for( re int k = 1; k < limit; k <<= 1 ) {
    			for( re int i = 0; i < limit; i += ( k << 1 ) )
    			for( re int j = i, d = num + 1; j < i + k; ++ j, ++ d ) {
    				int Nx = a[j], Ny = a[j + k] * ( ( type == 1 ) ? gi[d] : igi[d] ) % P ;
    				a[j] = ( Nx + Ny ) % P, a[j + k] = ( Nx - Ny + P ) % P ; 
    			} num += k ;
    		} 
    		if( type != 1 ) rep( i, 0, limit ) a[i] = a[i] * Inv % P ; 
    	}
    	
    	void NTT( vi& a, int type ) { //NTT多项式乘法 
    		for( re int i = 0; i < limit; ++ i ) if( i < R[i] ) swap( a[i], a[R[i]] ) ;
    		int num = 0 ;
    		for( re int k = 1; k < limit; k <<= 1 ) {
    			for( re int i = 0; i < limit; i += ( k << 1 ) )
    			for( re int j = i, d = num + 1; j < i + k; ++ j, ++ d ) {
    				int Nx = a[j], Ny = a[j + k] * ( ( type == 1 ) ? gi[d] : igi[d] ) % P ;
    				a[j] = ( Nx + Ny ) % P, a[j + k] = ( Nx - Ny + P ) % P ; 
    			} num += k ;
    		} 
    		if( type != 1 ) rep( i, 0, limit ) a[i] = a[i] * Inv % P ; 
    	}
    	void Mul(vi& a, vi& b) {
    		int l1 = a.size(), l2 = b.size() ; 
    		Init(l1 + l2), a.resize(limit + 1), b.resize(limit + 1) ;
    		NTT(a, 1), NTT(b, 1) ;
    		rep( i, 0, limit ) a[i] = a[i] * b[i] % P ; 
    		NTT(a, 0) ; int len = l1 + l2 ; 
    		rep( i, len, limit ) a[i] = 0 ;
    		a.resize(len) ;  
    	}
    	// 求逆 
    	int H[N], Gx[N] ;
    	void PolyInv( int *a, int x ) {
    		Gx[0] = fpow( a[0], P - 2 ) ; int lim = 1 ; 
    		while( lim < x ) {
    			lim <<= 1, Init( lim << 1 ) ; 
    			for( re int i = 0; i < lim; ++ i ) H[i] = a[i] ;
    			NTT( H, 1 ), NTT( Gx, 1 ) ;
    			for( re int i = 0; i < limit; ++ i ) Gx[i] = ( 2ll - Gx[i] * H[i] % P + P ) % P * Gx[i] % P ;
    			NTT( Gx, 0 ) ; for( re int i = lim; i < limit; ++ i ) Gx[i] = 0 ;
    		}
    		for( re int i = 0; i <= x; ++ i ) a[i] = Gx[i] ;
    		rep( i, 0, limit ) Gx[i] = H[i] = 0 ;
    	} 
    	void Deriv( int *a, int x ) { //求导 
    		rep( i, 1, x ) a[i - 1] = a[i] * i % P ;
    	}
    	void Integ( int *a, int x ) { //积分 
    		drep( i, 1, x ) a[i] = a[i - 1] * inv[i] % P ;
    		a[0] = 0 ;
    	}
    	int Gt[N], F[N] ;
    	void Polyln( int *a, int x ) {
    		rep( i, 0, x ) F[i] = Gt[i] = a[i] ;
    		PolyInv( Gt, x ), Deriv( F, x ) ; 
    		Init( x << 1 ), NTT( Gt, 1 ), NTT( F, 1 ) ;
    		rep( i, 0, limit ) F[i] = F[i] * Gt[i] % P ;
    		NTT( F, 0 ), Integ( F, x ) ;
    		rep( i, 0, x - 1 ) a[i] = F[i] ;
    		rep( i, 0, limit ) F[i] = Gt[i] = 0 ;
    	}
    	int _Gt[N], _F[N], _H[N] ; 
    	void Polyexp( int *a, int x ) {
    		_Gt[0] = 1 ; int lim = 1 ; 
    		while( lim < x ) {
    			lim <<= 1 ; rep( i, 0, lim - 1 ) _F[i] = a[i], _H[i] = _Gt[i] ;
    			Polyln( _H, lim ), Init( lim << 1 ) ;
    			NTT( _Gt, 1 ), NTT( _H, 1 ), NTT( _F, 1 ) ;
    			rep( i, 0, limit ) _Gt[i] = ( 1ll - _H[i] + _F[i] + P ) % P * _Gt[i] % P ;
    			NTT( _Gt, 0 ) ; rep( i, lim, limit ) _Gt[i] = 0 ;
    		}
    		rep( i, 0, x - 1 ) a[i] = _Gt[i] ;
    		rep( i, 0, limit ) _F[i] = _H[i] = _Gt[i] = 0 ;
    	}
    	void PolyKSM( int *a, int x, int k ) {
    		Polyln( a, x ) ;
    		rep( i, 0, x - 1 ) a[i] = a[i] * k % P ;
    		Polyexp( a, x ) ;
    	}
    	int _Nw[N], _Gx[N], _Gy[N], _Gz[N], _Go[N], _GG[N] ; 
    	void Newton(int *a, int x) {
    		_Nw[0] = 1 ; int lim = 1 ; 
    		while( lim < x ) {
    			lim <<= 1 ; rep( i, 0, lim - 1 ) _Gz[i] = _Gx[i] = _Gy[i] = _Nw[i] ; 
    			PolyKSM(_Gx, lim, m) ; 
    			rep( i, 0, lim ) _GG[i] = _Gx[i] ; 
    			Init(lim << 1) ;
    			NTT(_GG, 1), NTT(_Gy, 1) ;
    			rep( i, 0, limit ) _Gy[i] = _Gy[i] * _GG[i] % P ; 
    			NTT(_Gy, 0) ; 
    			rep( i, lim, limit ) _Gy[i] = 0 ; 
    			rep( i, 0, lim ) _Gx[i] = _Gx[i] * (m + 1) % P ; 
    			rep( i, 0, lim ) _Go[i] = _Gx[i], _Gx[i] = 0 ; 
    			rep( i, m, lim - 1 ) _Gx[i] = _Go[i - m] ; 
    			dec(_Gx[0], 1), dec(_Gx[1], 1), PolyInv(_Gx, lim) ; 
    			for(re int i = lim - 1; i; -- i) 
    			inc( _Gz[i], _Gz[i - 1] ) ;
    			rep( i, 0, lim ) _Go[i] = _Gy[i], _Gy[i] = 0 ; 
    			rep( i, m, lim - 1 ) _Gy[i] = _Go[i - m] ; 
    			rep( i, 0, lim ) dec(_Gy[i], _Gz[i]) ;
    			inc(_Gy[0], 1), Init(lim << 1) ; 
    			NTT(_Gx, 1), NTT(_Gy, 1) ; 
    			rep( i, 0, limit ) _Gx[i] = _Gx[i] * _Gy[i] % P ; 
    			NTT(_Gx, 0) ; 
    			rep( i, lim, limit ) _Gx[i] = 0 ; 
    			rep( i, 0, lim - 1 ) dec(_Nw[i], _Gx[i]) ; 
    		}
    		rep( i, 0, x - 1 ) a[i] = _Nw[i] ; 
    	} 
    }
    int top, st[N], fac2[N], inv2[N] ; 
    void solve(int l, int r) {
    	if(l == r) return ; 
    	int mid = (l + r) >> 1 ; 
    	solve(l, mid), solve(mid + 1, r) ; 
    	Poly::Mul(f[l], f[mid + 1]) ; 
    }
    int C(int x, int y) {
    	return 1ll * fac2[x] * inv2[y] % P * inv2[x - y] % P ; 
    }
    signed main()
    {
    	n = read(), m = read(), fac2[0] = inv2[0] = 1 ; 
    	rep( i, 1, n ) B[i] = read() ;
    	rep( i, 1, n ) fac2[i] = fac2[i - 1] * i % P ;
    	rep( i, 0, n ) inv2[i] = fpow(fac2[i], P - 2) ; 
    	Poly::_init(n * 2), Poly::Newton(A, n) ;
    	Poly::PolyInv(A, n) ; 
    	sort(B + 1, B + n + 1), B[0] = -1 ; int l = 0 ; 
    	rep( i, 1, n ) {
    		if(B[i] != B[i - 1] + 1) st[++ top] = l, l = 0 ; ++ l ; 
    	} st[++ top] = l ; 
    	for(re int i = 1; i <= top; ++ i) {
    		int u = st[i], iv = fpow(u + 1, P - 2) ; 
    		f[i].resize(u + 1) ;
    		rep( j, 0, u ) Dx[j] = A[j] ; 
    		Poly::PolyKSM(Dx, u + 1, u + 1) ;
    		rep( j, 1, u ) f[i][j] = j * Dx[u - j + 1] % P * iv % P ; 
    		rep( j, 1, u ) if((u - j + 1) > j) swap(f[i][j], f[i][u - j + 1]) ; 
    		f[i][0] = 1 ; 
    	} 
    	solve(1, top) ; 
    	int Ans = 0 ; 
    	rep( i, 1, n - 1 ) Ans = (Ans + f[1][i] * fpow(C(n, i), P - 2) % P * n % P * fpow(n - i, P - 2)) % P ; 
    	cout << (Ans + 1) % P << endl ; 
    	return 0 ;
    }
    
  • 相关阅读:
    最全的Pycharm debug技巧,「建议收藏」
    2种场景下的Docker配置的jerkins乱码处理
    is_unique 属性检查给定 Series 对象中的基础数据是否唯一
    【吐血整理】Python 常用模块(二):json 模块
    SDL 显示输入法候选框
    八十年代的歌 磊哥吉他谱
    【云服务器】推荐san、feng、yun服务器,目前永久免费!
    1.0Spring的“出生”
    写在之前-最近打算整理下Spring
    杂记-DIY电脑清单
  • 原文地址:https://www.cnblogs.com/Soulist/p/14255816.html
Copyright © 2020-2023  润新知