组合数学 + 概率论 - Set1 - HDU 6825

组合数学 + 概率论 - Set1 - HDU 6825

题意:

给 定 一 个 集 合 S = { 1 , 2 , . . . , n } , 每 次 删 除 当 前 集 合 中 的 最 小 元 素 , 同 时 再 随 机 删 除 一 个 元 素 , 直 到 ∣ S ∣ = 1 , 求 每 个 元 素 最 后 被 留 下 来 的 概 率 。 给定一个集合S=\lbrace 1,2,...,n\rbrace,每次删除当前集合中的最小元素,同时再随机删除一个元素,直到|S|=1,求每个元素最后被留下来的概率。 S={1,2,...,n}S=1

n 是 奇 数 , 答 案 对 998244353 取 模 。 n是奇数,答案对998244353取模。 n998244353

输入:

T ( 1 ≤ T ≤ 40 ) 组 测 试 数 据 , T(1\le T \le 40)组测试数据, T(1T40)

每 组 包 括 一 个 正 整 数 n 。 每组包括一个正整数n。 n

保 证 ∑ n ≤ 5 × 1 0 6 保证\sum n \le 5×10^6 n5×106

输出:

n 个 正 整 数 , 表 示 答 案 。 n个正整数,表示答案。 n

Sample Input

1
3

Sample Output

0 499122177 499122177

分析:

考 虑 第 i 个 元 素 被 留 下 来 , 前 有 i − 1 个 元 素 , 后 有 n − i 个 元 素 。 考虑第i个元素被留下来,前有i-1个元素,后有n-i个元素。 ii1ni

当 且 仅 当 n − i ≤ i − 1 时 , i 才 可 能 被 留 下 。 当且仅当n-i \le i-1时,i才可能被留下。 nii1i

记 每 次 删 除 最 小 的 元 素 为 操 作 1 , 随 即 删 除 一 个 元 素 为 操 作 2 。 记每次删除最小的元素为操作1,随即删除一个元素为操作2。 12

第 i 个 元 素 后 面 的 元 素 必 是 被 操 作 2 删 除 的 。 第i个元素后面的元素必是被操作2删除的。 i2

而 i 被 留 下 的 情 况 : 而i被留下的情况: i

① 、 一 定 是 i 后 面 的 n − i 个 元 素 与 前 i − 1 个 元 素 中 的 n − i 个 元 素 一 一 对 应 被 删 除 , ①、一定是i后面的n-i个元素与前i-1个元素中的n-i个元素一一对应被删除, inii1ni

② 、 接 着 从 前 ( i − 1 ) − ( n − i ) = 2 i − n − 1 个 元 素 中 , 两 两 选 择 删 除 , 直 至 剩 下 第 i 个 元 素 。 ②、接着从前(i-1)-(n-i)=2i-n-1个元素中,两两选择删除,直至剩下第i个元素。 (i1)(ni)=2in1i

对 于 情 形 ① , 我 们 先 要 从 前 i − 1 个 元 素 选 择 n − i 个 元 素 一 一 配 对 , 总 的 不 同 选 法 数 量 为 C i − 1 n − i , 对于情形①,我们先要从前i-1个元素选择n-i个元素一一配对,总的不同选法数量为C_{i-1}^{n-i}, i1niCi1ni

由 于 配 对 是 有 顺 序 的 , 对 于 每 一 种 选 法 , 都 对 应 ( n − i ) ! 种 不 同 的 方 案 , 故 ① 的 方 案 总 数 为 C i − 1 n − i × ( n − i ) ! 。 由于配对是有顺序的,对于每一种选法,都对应(n-i)!种不同的方案,故①的方案总数为C_{i-1}^{n-i}×(n-i)!。 (ni)!Ci1ni×(ni)!

对 于 情 形 ② , 此 时 i 为 最 后 一 个 元 素 , 现 从 前 2 i − n − 1 个 元 素 中 两 两 配 对 删 除 , 对于情形②,此时i为最后一个元素,现从前2i-n-1个元素中两两配对删除, i2in1

故 ② 的 方 案 总 数 为 故②的方案总数为

C 2 i − n − 1 2 × C 2 i − n − 3 2 × . . . × C 2 2 = ( 2 i − n − 1 ) ! ( 2 i − n − 1 − 2 ) ! ⋅ 2 ! × ( 2 i − n − 3 ) ! ( 2 i − n − 3 − 2 ) ! ⋅ 2 ! × . . . × 1 = ( 2 i − n − 1 ) ! 2 ! 2 i − n − 1 2 C_{2i-n-1}^2×C_{2i-n-3}^2×...×C_{2}^2=\frac{(2i-n-1)!}{(2i-n-1-2)!·2!}×\frac{(2i-n-3)!}{(2i-n-3-2)!·2!}×...×1=\frac{(2i-n-1)!}{2!^{\frac{2i-n-1}{2}}} C2in12×C2in32×...×C22=(2in12)!2!(2in1)!×(2in32)!2!(2in3)!×...×1=2!22in1(2in1)!

注意: 选 择 这 2 i − n − 1 2 对 , 顺 序 是 固 定 的 。 例 如 ( 1 , 3 ) 和 ( 2 , 4 ) , 必 然 是 先 删 除 ( 1 , 3 ) 再 删 除 ( 2 , 4 ) , 选择这\frac{2i-n-1}{2}对,顺序是固定的。例如(1,3)和(2,4),必然是先删除(1,3)再删除(2,4), 22in1(1,3)(2,4)(1,3)(2,4)

   这 个 顺 序 是 固 定 的 , 因 此 最 后 我 们 还 要 考 虑 这 2 i − n − 1 2 对 排 列 顺 序 的 影 响 , 故 将 上 式 再 除 ( 2 i − n − 1 2 ) ! 。 \qquad\ \ 这个顺序是固定的,因此最后我们还要考虑这\frac{2i-n-1}{2}对排列顺序的影响,故将上式再除(\frac{2i-n-1}{2})!。   22in1(22in1)!

综 上 , 元 素 i 被 留 下 来 的 方 案 总 数 为 : 综上,元素i被留下来的方案总数为: i

c n t [ i ] = C i − 1 n − i × ( n − i ) ! × ( 2 i − n − 1 ) ! 2 ! 2 i − n − 1 2   /   ( 2 i − n − 1 2 ) ! cnt[i]=C_{i-1}^{n-i}×(n-i)!×\frac{(2i-n-1)!}{2!^{\frac{2i-n-1}{2}}}\ /\ (\frac{2i-n-1}{2})! cnt[i]=Ci1ni×(ni)!×2!22in1(2in1)! / (22in1)!

方 案 总 数 为 : s u m = ∑ i = 1 n c n t [ i ] 方案总数为:sum=\sum_{i=1}^ncnt[i] :sum=i=1ncnt[i]

则 第 i 数 留 下 的 概 率 为 : 则第i数留下的概率为: i p [ i ] = c n t [ i ] s u m p[i]=\frac{cnt[i]}{sum} p[i]=sumcnt[i]

注意: 情 况 ② 仅 在 ( i − 1 ) ≥ ( n − i ) 时 才 会 被 计 算 , 避 免 数 组 越 界 。 情况②仅在(i-1)\ge(n-i)时才会被计算,避免数组越界。 (i1)(ni)

代码:

#include
#include
#include
#include
#include

#define ll long long

using namespace std;

const int N=5e6, mod=998244353;

int T, n;
int fac[N+10], inv[N+10], inv_fac2[N+10];
int cnt[N+10];

int quick_pow(int a,int b, int mod)
{
    int res=1;
    while(b)
    {
        if(b&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
        b>>=1;
    }
    return res;
}

void Init()
{
    fac[0]=1;
    for(int i=1;i<=N;i++) fac[i]=(ll)fac[i-1]*i%mod;
    
    inv[N]=quick_pow(fac[N],mod-2,mod);
    for(int i=N-1;i>=0;i--) inv[i]=(ll)inv[i+1]*(i+1)%mod;
    
    inv_fac2[0]=1;
    inv_fac2[1]=quick_pow(2,mod-2,mod);
    for(int i=2;i<=N;i++) inv_fac2[i]=(ll)inv_fac2[i-1]*inv_fac2[1]%mod;
}

int C(int n,int m)
{
    if(n<m) return 0;
    return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main()
{
    Init();

    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        int sum=0;
        for(int i=1;i<=n/2;i++) cnt[i]=0;
        for(int i=n/2+1;i<=n;i++) 
        {
            cnt[i]=(ll)C(i-1,n-i)*fac[n-i]%mod;
            if(i-1>n-i) cnt[i]=(ll)cnt[i]*fac[2*i-n-1]%mod*inv[(2*i-n-1)/2]%mod*inv_fac2[(2*i-n-1)/2]%mod;
            sum=(sum+cnt[i])%mod;
        }
        
        sum=quick_pow(sum,mod-2,mod);
        for(int i=1;i<=n;i++) {printf("%d",(ll)cnt[i]*sum%mod);if(i!=n) printf(" ");}
        puts("");
    }
    return 0;
}

你可能感兴趣的:(数论,概率论,算法,组合数学,概率论,ACM)