传送门: 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出现的次数。 所以我们针对每个数字1,2...n出现的次数,即贡献为numi∗i!1,numi表示i出现的次数。
即 a n s = ∑ i = 1 n n u m i ∗ 1 i ! 即ans=\sum_{i=1}^{n}num_i*\frac{1}{i!} 即ans=∑i=1nnumi∗i!1
比
如
先
考
虑
1
,
先
拿
出
一
个
1
,
然
后
还
剩
下
n
−
1
,
则
我
们
让
他
们
随
意
组
合
。
比如先考虑1,先拿出一个1,然后还剩下n-1,则我们让他们随意组合。
比如先考虑1,先拿出一个1,然后还剩下n−1,则我们让他们随意组合。
假
设
n
−
1
组
成
4
个
数
字
,
则
由
捆
绑
法
可
得
:
假设n-1组成4个数字,则由捆绑法可得:
假设n−1组成4个数字,则由捆绑法可得:
n − 1 的 组 成 4 个 数 字 的 种 数 为 C n − 2 3 , 然 后 我 们 的 1 可 以 插 入 5 个 位 置 , 则 ∗ 5. n-1的组成4个数字的种数为C_{n-2}^{3},然后我们的1可以插入5个位置,则*5. n−1的组成4个数字的种数为Cn−23,然后我们的1可以插入5个位置,则∗5.
我
们
可
以
让
n
−
1
组
成
1
到
n
−
1
个
数
字
,
进
而
得
出
,
1
出
现
的
总
次
数
为
:
我们可以让n-1组成1到n-1个数字,进而得出,1出现的总次数为:
我们可以让n−1组成1到n−1个数字,进而得出,1出现的总次数为:
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
Cn−20∗2+Cn−21∗3+...+Cn−2n−3∗(n−1)+Cn−2n−2∗n
由 组 合 恒 等 式 算 出 来 , 这 个 式 子 为 2 n − 1 + ( n − 2 ) ∗ 2 n − 3 由组合恒等式算出来,这个式子为2^{n-1}+(n-2)*2^{n-3} 由组合恒等式算出来,这个式子为2n−1+(n−2)∗2n−3
则 1 的 总 贡 献 为 1 1 ! ∗ ( 2 n − 1 + ( n − 2 ) ∗ 2 n − 3 ) 则1的总贡献为\frac{1}{1!}*(2^{n-1}+(n-2)*2^{n-3}) 则1的总贡献为1!1∗(2n−1+(n−2)∗2n−3)
然 后 计 算 2 , 3 一 直 到 n 的 贡 献 , 加 起 来 即 可 。 注 意 一 些 边 界 问 题 , 越 界 了 都 当 成 0. 然后计算2,3一直到n的贡献,加起来即可。注意一些边界问题,越界了都当成0. 然后计算2,3一直到n的贡献,加起来即可。注意一些边界问题,越界了都当成0.
分
母
就
是
n
个
1
能
有
多
少
种
组
成
方
法
:
分母就是n个1能有多少种组成方法:
分母就是n个1能有多少种组成方法:
组
成
1
个
数
,
C
n
−
1
0
组成1个数,C_{n-1}^{0}
组成1个数,Cn−10
组
成
2
个
数
,
C
n
−
1
1
组成2个数,C_{n-1}^{1}
组成2个数,Cn−11
…
组
成
n
个
数
字
,
C
n
−
1
n
−
1
组成n个数字,C_{n-1}^{n-1}
组成n个数字,Cn−1n−1
由 二 项 式 定 理 得 , 分 母 为 2 n − 1 由二项式定理得,分母为2^{n-1} 由二项式定理得,分母为2n−1
总 结 一 下 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}} 2n−1∑i=1n2n−i+(n−i−1)∗2n−i−2
预 处 理 然 后 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();
}