noi.ac 集合

A.集合



题面

不知道有没有用的传送门【滑稽

就是给你一个 包含 1~n 的集合,让你求它的大小为 k 的子集 s 的 \(T^{min(s)}\) 的期望值, T 为给出值, min(s) 表示 s 集合中的最小值

一般的,答案可以写作:

\[ANS=E(T^{min(s)} | s∈[n] ,|s|=k) \]

其中 \([n]\) 表示 1~n 的全集 , \(|s|\) 表示集合 s 的大小(元素个数)

一道二项式定理的例题?虽说我根本做不到二项式定理那一步 23333

首先我们转化一下答案表达式,让它更可做:

\[ANS=\sum_{i=1}^n T^i ( ~^{n-i}_{k-1} ) \]

式子的意思就是说,我们先选择一个最小值,然后在比他大的元素中选出 k-1 个

至于这里为什么 i 从 1 到 k ? 因为 \(n-i\)\(k-1\) 小的话不会产生贡献所以不会影响答案咯

然后我们发现答案也可以这么表示:

\[ANS=T( ~^{n}_k )+\sum_{i=1}^{n-1} (T-1)T^i (~^{n-i}_{~~~ k}) \]

然后我们发现这里后面的式子就是 k+1 时的 ANS ,于是我们就可以一直这么递归下去,那么答案就可以表示为:

\[ANS= T \sum_{i=k}^n (T-1)^{i-k}(~^{n}_i) \]

\[ANS= T(T-1)^{-k} \sum_{i=k}^n (T-1)^{i}(~^{n}_i) \]

用二项式定理化式子:

\[ANS= T (T-1)^{-k}~(T^n-\sum_{i=0}^{k-1} (T-1)^i(~^{n}_i)) \]

到了这里就非常可做了,因为后面的求和是 \(O(k)\) 的,至于组合数?看代码你就知道怎么处理了,然后就是快速幂打打就好了

但还有一个问题,我们要求期望,也就是说算出来的答案要除去方案数,方案数比较好想,就是:\(\sum_{i=1}^{n} (~_{k-1}^{n-i})\) ,这个怎么算?

我们把式子弄好看些:

\[\sum_{i=0}^{n-1} (~_{k-1}^{~~~i}) \]

其实这个东西的答案就是 \((~_ k^n)\) ,这个我们画画杨辉三角然后发现这玩意儿是一列下来的,然后加个零,一路加下来就发现答案停留在 \(C(n,k)\)

code

//by Judge
#include<cstdio>
#include<cstring>
#include<iostream>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define ll long long
using namespace std;
const int mod=998244353;
const int M=1e7+3; typedef int arr[M];
inline int mul(R int x,R int y){return 1ll*x*y%mod;}
inline int inc(R int x,R int y){return x+y>=mod?x+y-mod:x+y;}
inline int qpow(R int x,R int p=mod-2){ R int s=1;
	for(;p;p>>=1,x=mul(x,x)) if(p&1) s=mul(s,x); return s;
} int n,k,T,ans,nC,nT; arr V,F;
int main(){ cin>>n>>k>>T,
	ans=qpow(T,n),
    	nT=nC=V[0]=V[1]=F[0]=F[1]=1;
	if(T==1) return !puts("1");
	fp(i,2,k)
		V[i]=mul(V[mod%i],mod-mod/i),
		F[i]=mul(F[i-1],V[i]);
	fp(i,0,k-1)
		ans=inc(ans,mod-mul(nT,mul(nC,F[i]))),
		nC=mul(nC,n-i),nT=mul(nT,T-1);
	return !printf("%d\n",mul(mul(ans,mul(T,qpow(nT))),qpow(mul(nC,F[k]))));
}

可以看到上面处理组合数的方式是维护下降幂, 然后乘上 \(O(k)\) 处理出来的阶乘逆元 !简直不要太骚...

posted @ 2019-04-02 14:37  Jμdge  阅读(447)  评论(0编辑  收藏  举报