Educational Codeforces Round 78 (Rated for Div. 2) F. Cards 第二类斯特林数

题意

给你洗 n n n次牌,这副牌有m张牌,其中有一个大王,你每次会抽出最顶的一张然后看完之后就放回去,假设你看过x次大王,你的贡献就是x^k,求期望贡献

分析

题目就是要求
= ∑ i = 1 n ( n i ) i k ( m − 1 ) n − i m n =\frac{\sum\limits_{i=1}^{n} \binom{n}{i} i^k(m-1)^{n-i}}{m^n} =mni=1n(in)ik(m1)ni
然后一看这种形式大多就用第二斯特林数展开
n k = ∑ i = 0 k S ( k , i ) i ! ( n i ) n^k = \sum\limits_{i=0}^{k}S(k,i)i!\binom{n}{i} nk=i=0kS(k,i)i!(in)

= ∑ i = 1 n ( n i ) ∑ j = 0 m i n ( i , k ) S ( k , j ) j ! ( i j ) ( m − 1 ) n − i m n =\frac{\sum\limits_{i=1}^{n}\binom{n}{i}\sum\limits_{j=0}^{min(i,k)}S(k,j)j!\binom{i}{j}(m-1)^{n-i}}{m^n} =mni=1n(in)j=0min(i,k)S(k,j)j!(ji)(m1)ni

= ∑ j = 0 m i n ( n , k ) S ( k , j ) ∑ i = j n n ! ( n − i ) ! ( i − j ) ! ( m − 1 ) n − i m n =\frac{\sum\limits_{j=0}^{min(n,k)}S(k,j)\sum\limits_{i=j}^{n} \frac{n!}{(n-i)!(i-j)!} (m-1)^{n-i}}{m^n} =mnj=0min(n,k)S(k,j)i=jn(ni)!(ij)!n!(m1)ni

考虑n很大,把后面带n的部分去掉

= ∑ j = 0 m i n ( n , k ) S ( k , j ) n ! ( n − j ) ! ∑ i = 0 n − j ( n − j i ) ( m − 1 ) n − i − j m n =\frac{\sum\limits_{j=0}^{min(n,k)}S(k,j)\frac{n!}{(n-j)!}\sum\limits_{i=0}^{n-j}\binom{n-j}{i}(m-1)^{n-i-j}}{m^n} =mnj=0min(n,k)S(k,j)(nj)!n!i=0nj(inj)(m1)nij

用二项式定理合并之后就行了

= ∑ j = 0 m i n ( n , k ) S ( k , j ) n ! ( n − j ) ! m n − j m n =\frac{\sum\limits_{j=0}^{min(n,k)}S(k,j)\frac{n!}{(n-j)!}m^{n-j}}{m^n} =mnj=0min(n,k)S(k,j)(nj)!n!mnj

代码

#include 
#define pb push_back
#define MP make_pair
#define fi first
#define se second
 
using namespace std;
 
typedef long long ll;
typedef pair<ll,ll> pii;
 
const ll N = 1000010;
const ll inf = 1e9;
const ll mod = 998244353;
 
inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

ll qpow(ll x,ll k,ll mo)
{
  ll s = 1;
  while(k)
  {
    if(k&1) s=s*x%mo;
    x=x*x%mo; k>>=1;
  }return s;
}

ll n,m,k,S[5010][5010];

int main()
{
  n = read(); m = read(); k = read();
  S[0][0] = 1; S[1][0] = 0;
  for(ll i=1;i<=k;i++) for(ll j=0;j<=k;j++)
  {
    if(j==0) S[i][j] = 0;
    else S[i][j] = (S[i-1][j-1] + S[i-1][j] * j % mod) % mod;
  	// printf("%lld %lld : %lld\n",i,j,S[i][j]);
  }
  
  ll s=1; ll ans = 0; ll mb = qpow(m,n,mod); ll invm = qpow(m,mod-2,mod); // printf("%lld\n",invm);
  for(ll j=0;j<=min(n,k);j++)
  {
    ans = (ans + S[k][j] * s % mod * mb % mod) % mod;
	mb = mb * invm % mod,s = s * (n-j) % mod;
	// if(ans < 0) printf("%lld\n",j);
  }// printf("%lld\n",ans);
  return printf("%lld\n",ans * qpow(qpow(m,n,mod),mod-2,mod) % mod),0;
}

你可能感兴趣的:(Codeforces,斯特数,数学)