牛客挑战赛50 B Random eat Cake 排列组合

牛客挑战赛50 B Random eat Cake 排列组合


传送门: https://ac.nowcoder.com/acm/contest/11190/B

题意

在这里插入图片描述

思路

排 列 组 合 题 , 基 本 都 是 考 虑 “ 数 ” 的 贡 献 。 排列组合题,基本都是考虑“数”的贡献。

所 以 我 们 针 对 每 个 数 字 1 , 2... n 出 现 的 次 数 , 即 贡 献 为 n u m i ∗ 1 i ! , n u m i 表 示 i 出 现 的 次 数 。 所以我们针对每个数字1,2...n出现的次数,即贡献为num_i*\frac{1}{i!},num_i表示i出现的次数。 12...nnumii!1numii

即 a n s = ∑ i = 1 n n u m i ∗ 1 i ! 即ans=\sum_{i=1}^{n}num_i*\frac{1}{i!} ans=i=1nnumii!1

比 如 先 考 虑 1 , 先 拿 出 一 个 1 , 然 后 还 剩 下 n − 1 , 则 我 们 让 他 们 随 意 组 合 。 比如先考虑1,先拿出一个1,然后还剩下n-1,则我们让他们随意组合。 11n1
假 设 n − 1 组 成 4 个 数 字 , 则 由 捆 绑 法 可 得 : 假设n-1组成4个数字,则由捆绑法可得: n14:

n − 1 的 组 成 4 个 数 字 的 种 数 为 C n − 2 3 , 然 后 我 们 的 1 可 以 插 入 5 个 位 置 , 则 ∗ 5. n-1的组成4个数字的种数为C_{n-2}^{3},然后我们的1可以插入5个位置,则*5. n14Cn23155.

我 们 可 以 让 n − 1 组 成 1 到 n − 1 个 数 字 , 进 而 得 出 , 1 出 现 的 总 次 数 为 : 我们可以让n-1组成1到n-1个数字,进而得出,1出现的总次数为: n11n11
C n − 2 0 ∗ 2 + C n − 2 1 ∗ 3 + . . . + C n − 2 n − 3 ∗ ( n − 1 ) + C n − 2 n − 2 ∗ n C_{n-2}^{0}*2+C_{n-2}^{1}*3+...+C_{n-2}^{n-3}*(n-1)+C_{n-2}^{n-2}*n Cn202+Cn213+...+Cn2n3(n1)+Cn2n2n

由 组 合 恒 等 式 算 出 来 , 这 个 式 子 为 2 n − 1 + ( n − 2 ) ∗ 2 n − 3 由组合恒等式算出来,这个式子为2^{n-1}+(n-2)*2^{n-3} 2n1+(n2)2n3

则 1 的 总 贡 献 为 1 1 ! ∗ ( 2 n − 1 + ( n − 2 ) ∗ 2 n − 3 ) 则1的总贡献为\frac{1}{1!}*(2^{n-1}+(n-2)*2^{n-3}) 11!1(2n1+(n2)2n3)

然 后 计 算 2 , 3 一 直 到 n 的 贡 献 , 加 起 来 即 可 。 注 意 一 些 边 界 问 题 , 越 界 了 都 当 成 0. 然后计算2,3一直到n的贡献,加起来即可。注意一些边界问题,越界了都当成0. 23n0.

分 母 就 是 n 个 1 能 有 多 少 种 组 成 方 法 : 分母就是n个1能有多少种组成方法: n1:
组 成 1 个 数 , C n − 1 0 组成1个数,C_{n-1}^{0} 1Cn10
组 成 2 个 数 , C n − 1 1 组成2个数,C_{n-1}^{1} 2Cn11

组 成 n 个 数 字 , C n − 1 n − 1 组成n个数字,C_{n-1}^{n-1} n,Cn1n1

由 二 项 式 定 理 得 , 分 母 为 2 n − 1 由二项式定理得,分母为2^{n-1} 2n1

总 结 一 下 a n s : 总结一下ans: ans

∑ i = 1 n 2 n − i + ( n − i − 1 ) ∗ 2 n − i − 2 2 n − 1 \frac{\sum_{i=1}^{n}2^{n-i}+(n-i-1)*2^{n-i-2}}{2^{n-1}} 2n1i=1n2ni+(ni1)2ni2

预 处 理 然 后 O ( n ) 计 算 。 预处理然后O(n)计算。 O(n)

Code

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

typedef long long ll;

const ll mod = 998244353;
const int N = 5e5 + 10;

ll fac[N], inv[N], invF[N];
ll bit[N], invbit[N];

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

void init() {
    ll inv2 = quick_pow(2, mod - 2);
    invbit[0] = bit[0] = fac[0] = fac[1] = inv[0] = inv[1] = invF[0] = invF[1] = 1;
    bit[1] = 2;
    invbit[1] = inv2;
    for(int i = 2;i < N; i++) {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
        invF[i] = invF[i - 1] * inv[i] % mod;
        bit[i] = bit[i - 1] * 2 % mod;
        invbit[i] = invbit[i - 1] * inv2 % mod;
    }
}

void solve() {
    init();
    int _; cin >> _;
    while(_--) {
        int n; cin >> n;
        ll ans = 0;
        for(int i = 1;i <= n; i++) {
            ans = (ans + invF[i] * (bit[n - i] + (n - i - 1 >= 0 ? n - i - 1 : 0) * bit[(n - i - 2 >= 0 ? n - i - 2 : 0)] % mod) % mod) % mod;
        }
        ans = ans * invbit[n - 1] % mod;
        cout << (ans % mod + mod) % mod << endl;
    }
}

signed main() {
    solve();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值