HDU 6825 Set1(组合数学+数学推导)

原题链接:Set1
题面:

HDU 6825 Set1(组合数学+数学推导)_第1张图片

题目大意:

给定一个集合 S = { 1 ∼ n } S=\{1\sim n\} S={1n},对集合进行如下操作直到 ∣ S ∣ = 1 |S|=1 S=1
首先会先删除集合中最小的数,之后以相同的概率删除其他的数。
求集合中每一个数被保留下来的概率。

数学推导:

令操作 1 1 1为删除最小的元素,操作 2 2 2为随机删除一个元素。

假设元素 i i i 会被保留下来,则它的前面有 i − 1 i-1 i1 个元素,后面有 n − i n-i ni 个元素。我们需要考虑保留下元素 i i i 的所有方案数。

显然,保留下 i i i 必须满足的条件是: n − i ≤ i − 1 n-i\leq i-1 nii1。这样,我们可以知道,当 i ≤ n 2 i\leq \frac{n}{2} i2n 时, i i i 是必定会被删除的。而且,后面 n − i n-i ni 个元素必然是经过操作2删除的。

所以,在所有 i i i 被保留下来的情况中,后面 n − i n-i ni 个元素必然是与前面 i − 1 i-1 i1 个元素中的 n − i n-i ni 个元素一一对应被删去的。
所以,我们可以得到删除后面 n − i n-i ni 个元素的方案数为: C n − 1 i − 1 ∗ A n − i n − i = A i − 1 n − i = ( i − 1 ) ! ( 2 ∗ i − n − 1 ) ! C_{n-1}^{i-1}*A_{n-i}^{n-i}=A_{i-1}^{n-i}=\cfrac{(i-1)!}{(2*i-n-1)!} Cn1i1Anini=Ai1ni=(2in1)!(i1)!
删除后面 n − i n-i ni 个元素后,还剩下 2 ∗ i − n − 1 2*i-n-1 2in1 个元素没有删去,所以我们需要两两删除这些剩余的元素。
两两删除的方案数为: C 2 i − n − 1 2 ∗ C 2 i − n − 3 2 ∗ . . . ∗ C 2 2 = ( 2 i − n − 1 ) ! 2 ! 2 i − n − 1 2 C_{2i-n-1}^{2}*C_{2i-n-3}^{2}*...*C_{2}^{2}=\cfrac{(2i-n-1)!}{2!^{\frac{2i-n-1}{2}}} C2in12C2in32...C22=2!22in1(2in1)!
其中,由于选择存在顺序不一样,但是删除的元素重复的问题。所以,我们还需要进行去重操作。即需要除以 ( 2 i − n − 1 2 ) ! (\frac{2i-n-1}{2})! (22in1)!

最终得到的 i i i 被保留下来的方案数为: c n t [ i ] = ( i − 1 ) ! ( 2 ! ) 2 i − n − 1 2 ∗ ( 2 i − n − 1 2 ) ! cnt[i]=\cfrac{(i-1)!}{(2!)^\frac{2i-n-1}{2}*(\frac{2i-n-1}{2})!} cnt[i]=(2!)22in1(22in1)!(i1)!

总方案数 s u m = ∑ i = 1 n c n t [ i ] sum=\sum_{i=1}^{n}cnt[i] sum=i=1ncnt[i]
所以,元素 i i i 被保留的概率 p [ i ] = c n t [ i ] s u m p[i]=\cfrac{cnt[i]}{sum} p[i]=sumcnt[i]
这样,我们只需要预处理一下阶乘和逆元就行了。

代码:
#include 
#define sc scanf
#define pf printf
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 5e6 + 10, M = 2e4 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const int mod = 998244353;

LL fac[N], inv[N], invf[N], cnt[N];

LL qmi(LL a, LL b)
{
    LL ans = 1 % mod;
    for( ; b; b >>= 1) {
        if(b & 1)   ans = ans * a % mod;
        a = a * a % mod;
    }
    return ans;
}

void init()
{
    fac[0] = inv[0] = 1;
    for(int i = 1; i < N; i++) {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = inv[i - 1] * qmi(i, mod - 2) % mod;
    }
}

void solve()
{
    int n;
    sc("%d", &n);
    if(n == 1)  pf("1");
    else {
        LL sum = 0;
        for(int i = 1; i <= n >> 1; i++) pf("0 ");
        for(int i = n / 2 + 1; i <= n; i++) {
            cnt[i] = fac[i - 1] * qmi(inv[2], (2 * i - n - 1) / 2) % mod * inv[(2*i-n-1)/2] % mod;
            sum = (sum + cnt[i]) % mod;
        }
        sum = qmi(sum, mod - 2);
        for(int i = n / 2 + 1; i <= n; i++) {
            if(i == n / 2 + 1)  pf("%lld", sum * cnt[i] % mod);
            else  pf(" %lld", sum * cnt[i] % mod);
        }
    }
    puts("");
}

int main()
{
    init();
    int t; sc("%d", &t); while(t--) solve();
    return 0;
}

你可能感兴趣的:(HDU 6825 Set1(组合数学+数学推导))