• UOJ449. 【集训队作业2018】喂鸽子


    UOJ449. 【集训队作业2018】喂鸽子

    题目描述

    小Z是养鸽子的人。一天,小Z给鸽子们喂玉米吃。一共有n只鸽子,小Z每秒会等概率选择一只鸽子并给他一粒玉米。一只鸽子饱了当且仅当它吃了的玉米粒数量(ge k)
    小Z想要你告诉他,期望多少秒之后所有的鸽子都饱了。
    假设答案的最简分数形式为(frac{a}{b}),你需要求出(w),满足(a equiv b cdot w pmod{998244353} ; (0 le w lt 998244353))

    数据范围

    本题采用子任务的方式评测。
    子任务一((4pts)):(n = 1).
    子任务二((11pts)):(k = 1)
    子任务三((19pts)):(k = 2)
    子任务四((46pts)):(k le 50)
    子任务五((20pts)):无特殊限制。
    对于所有的数据,(n le 50)(k le 1000)
    时间限制:( exttt{1s})
    空间限制:( exttt{256MB})

    解题思路

    这题比较神仙,但如果能概率计数非常熟练,这题不是问题(反正我问题大了

    讲一个我能理解的⑧/kk

    一眼 (min-max) 容斥,将最后一个转化为第一个喂饱的 (ans = sum_{S} (-1)^{|S|+1}frac nif[s])

    (frac ni) 是为了去除喂到集合外的情况数

    [f[i] = sum_{j=0}^{(i-1)(k-1)} (frac 1i)^{j+k} *i*(j+k)*{j+k-1choose j}g[i-1][j]\ g[i-1][j] = (sum_{i=0}^{k-1}frac {x^i}{i!})^{i-1}[j] ]

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x)
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar('
    ');
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int N = 65, K = 3005;
    const int P = 998244353, G = 3;
    ll jie[2000050], inv[2000050], g[N][K*N], n, k;
    int lim, L, r[K*N];
    
    ll C(ll n, ll m) { return jie[n] * inv[m] % P * inv[n-m] % P; }
    
    ll fpw(ll x, ll mi) {
    	ll res = 1;
    	while (mi) {
    		if (mi & 1) res = res * x % P;
    		x = x * x % P, mi >>= 1;
    	}
    	return res;
    }
    
    void NTT(ll *a, int ty) {
    	for (int i = 0;i < lim; i++)
    		if (r[i] > i) swap(a[i], a[r[i]]);
    	for (int i = 1;i < lim; i <<= 1) {
    		ll wn = fpw(G, (P - 1) / (i << 1));
    		for (int j = 0;j < lim; j += (i << 1)) {
    			ll w = 1;
    			for (int k = 0;k < i; k++, w = w * wn % P) {
    				ll x = a[j + k], y = a[i + j + k] * w % P;
    				a[j + k] = (x + y) % P, 
    				a[i + j + k] = (x - y + P) % P;
    			}
    		}
    	}
    	if (ty == -1) {
    		ll inv = fpw(lim, P - 2);
    		for (int i = 0;i < lim; i++) a[i] = a[i] * inv % P;
    		reverse(a + 1, a + lim);
    	}
    }
    
    int main() {
    	read(n), read(k); lim = n * k + k;
    	inv[0] = inv[1] = jie[0] = jie[1] = 1;
    	for (int i = 2;i <= lim; i++) 
    		inv[i] = (P - P / i) * inv[P%i] % P,
    		jie[i] = jie[i-1] * i % P;
    	for (int i = 2;i <= lim; i++) inv[i] = inv[i-1] * inv[i] % P;
    	for (int i = 0;i < k; i++) g[1][i] = inv[i];
    	lim = 1; while (lim <= n * k) lim <<= 1, L++;
    	for (int i = 1;i < lim; i++)
    		r[i] = (r[i>>1] >> 1) | ((i & 1) << (L - 1));
    	NTT(g[1], 1), g[0][0] = 1;
    	for (int i = 2;i < n; i++)
    		for (int j = 0;j < lim; j++) g[i][j] = g[1][j] * g[i-1][j] % P;
    	NTT(g[1], -1);
    	for (int i = 2;i < n; i++) NTT(g[i], -1);
    	ll ans = 0;
    	for (int i = 1;i <= n; i++) {
    		ll res = 0;
    		for (int j = 0;j <= (i - 1) * k; j++)
    			res = (res + fpw(i, P - 1 - j - k) * (j + k) % P * C(j + k - 1, j) % P * g[i-1][j] % P * jie[j]) % P;
    		res = res * C(n, i) % P;
    //		cout << res * n % P << endl;
    		if (i & 1) ans += res;
    		else ans -= res; ans %= P;
    	}
    	return write((ans * n % P + P) % P), 0;
    }
    

    还有另一种方法

    处理 (g[i][j]) 的方法相同

    [ans = sum_{i=1}^n(-1)^{i+1} *frac ni*sum_{j=0}^{i * (k-1)} frac {g[i][j]}{i^j} ]

    这个式子就要简单多了

    [sum_{i=1}^n i * P(i) = sum_{i=0}^nP(x>i) ]

    这样可以将期望转化为概率,挺好用

  • 相关阅读:
    Socket
    利用Python自动生成暴力破解的字典
    【转】六年测试工作的思考1
    【转】手机测试入行三年的感想
    【转】移动测试人员的未来:测试开发技术的融合
    【转】一个互联网项目即将结束的软件测试经验总结
    【转】电子商务网站测试经验总结
    【转】六年软件测试感悟-从博彦到VMware
    使用PL/SQL删除百万条记录的大表
    【转】百万级数据查询优化
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12907228.html
Copyright © 2020-2023  润新知