题意
有
n种不同的物品,每秒会随机产生一种,其中第
i秒的代价是
ik。问收集到所有物品的期望代价和,答案模
998244353。
1≤n≤100,0≤k≤100。
题解
显然是minmax容斥。
ans=∑i=1n(−1)i+1(in)f(ni,k)。
这里
f(p,k)表示每次试验成功概率为
p,最早成功时间为
T,
∑i=1Tik的期望。
f(p,k)是关于通常幂的式子,不好求,容易想到通过第二类斯特林数转成下降幂来算,具体的有
f(p,k)=∑i≥0(1−p)i(i+1)k=∑i≥0(1−p)i∑j=0ks(k,j)j!(ji+1)。
交换求和顺序有
f(p,k)=∑j=0ks(k,j)j!∗g(1−p,j),其中
g(p,k)=∑i≥0pi(ki+1)。
当
k=0时,
g(p,0)=∑i≥0pi=1−p1。
当
k=1时,
g(p,1)=∑i≥0pi(1i+1)=(∑i≥0pi∗i)+p∗(∑i≥0pi(1i+1)),于是
g(p,1)=1−pg(p,0)=(1−p)21。
当
k>1时,
g(p,k)=∑i≥0pi(ki+1)=∑i≥k−1pi(ki+1)=p∗(∑i≥k−2pi∗(k−1i+1))+p∗(∑i≥k−1pi(ki+1)),于是
g(p,k)=1−pp∗g(p,k−1)=(1−p)k+1pk−1(k>1)。
直接按式子计算即可,时间复杂度
O(nk)。
#include <bits/stdc++.h>
#define MOD 998244353
using namespace std;
typedef long long ll;
ll pow_mod(ll x,int k) {
ll ans=1;
while (k) {
if (k&1) ans=ans*x%MOD;
x=x*x%MOD;
k>>=1;
}
return ans;
}
ll C[105][105],strl[105][105],facd[105];
void pre(int n) {
for(int i=0;i<=n;i++) C[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
strl[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++) strl[i][j]=(strl[i-1][j-1]+j*strl[i-1][j])%MOD;
facd[0]=1;
for(int i=1;i<=n;i++) facd[i]=facd[i-1]*i%MOD;
}
int main() {
int n,k;
scanf("%d%d",&n,&k);
pre(max(n,k));
ll ans=0;
for(int i=1;i<=n;i++) {
ll p=i*pow_mod(n,MOD-2)%MOD,q=(1LL-p+MOD)%MOD;
p=pow_mod(p,MOD-2);
ll cur=p,s=0;
for(int j=0;j<=k;j++) {
s=(s+cur*strl[k][j]%MOD*facd[j])%MOD;
if (j) cur=cur*p%MOD*q%MOD;
else cur=cur*p%MOD;
}
ans=(ans+s*C[n][i]%MOD*((i&1)?1:MOD-1))%MOD;
}
printf("%lld\n",ans);
return 0;
}
附记
这是一个水题。
为什么要为这个题写博呢?因为我闹了笑话。
今天模拟赛出了这题,然后我花了5min秒了,然后dcx也秒了。后来他找我说他觉得数据错了,我跟他对了一下100 100的输出,是一样的,于是找到zjt要求改数据。然而场上并没有其他人写了正解或是自以为正解的东西,于是就照我们的做法造了数据。
晚上被zjt找到我们,要我们测测1 1的数据,结果发现输出了0。
这是怎么回事呢?冷静推演了很久,发现我在推式子的时候把
(i+1)k当做了
ik来算,大体上是一样的(可以自己推推)。唯一区别是在
k=1时,并不需要特判,也就是
g(p,k)=(1−p)k+1pk(k>0)。
为什么输出会撞上呢?问了问dcx,虽然我们推的式子不同,可是都把
(i+1)k当成了
ik。
最后发现原来的数据是对的,感觉极度尴尬。
自闭了。
扩展
稍微推导一下,发现运用等幂和其实可以做到
O(nlog2n)的复杂度。代码还没有。