当前位置: 代码迷 >> 综合 >> XSY #2815 净空
  详细解决方案

XSY #2815 净空

热度:39   发布时间:2023-12-23 23:27:58.0
题意

nnn种不同的物品,每秒会随机产生一种,其中第iii秒的代价是iki^kik。问收集到所有物品的期望代价和,答案模998244353998244353998244353
1≤n≤100,0≤k≤1001\leq n\leq100,0\leq k\leq1001n100,0k100

题解

显然是minmax容斥。
ans=∑i=1n(?1)i+1(ni)f(in,k)ans=\sum_{i=1}^{n}(-1)^{i+1}{n \choose i}f(\frac{i}{n},k)ans=i=1n?(?1)i+1(in?)f(ni?,k)
这里f(p,k)f(p,k)f(p,k)表示每次试验成功概率为ppp,最早成功时间为TTT∑i=1Tik\sum_{i=1}^{T}i^ki=1T?ik的期望。
f(p,k)f(p,k)f(p,k)是关于通常幂的式子,不好求,容易想到通过第二类斯特林数转成下降幂来算,具体的有f(p,k)=∑i≥0(1?p)i(i+1)k=∑i≥0(1?p)i∑j=0ks(k,j)j!(i+1j)f(p,k)=\sum_{i\geq 0}(1-p)^i(i+1)^k=\sum_{i\geq 0}(1-p)^i\sum_{j=0}^{k}s(k,j)j!{i+1 \choose j}f(p,k)=i0?(1?p)i(i+1)k=i0?(1?p)ij=0k?s(k,j)j!(ji+1?)
交换求和顺序有f(p,k)=∑j=0ks(k,j)j!?g(1?p,j)f(p,k)=\sum_{j=0}^{k}s(k,j)j!*g(1-p,j)f(p,k)=j=0k?s(k,j)j!?g(1?p,j),其中g(p,k)=∑i≥0pi(i+1k)g(p,k)=\sum_{i\geq 0}p^i{i+1 \choose k}g(p,k)=i0?pi(ki+1?)
k=0k=0k=0时,g(p,0)=∑i≥0pi=11?pg(p,0)=\sum_{i\geq 0}p^i=\frac{1}{1-p}g(p,0)=i0?pi=1?p1?
k=1k=1k=1时,g(p,1)=∑i≥0pi(i+11)=(∑i≥0pi?i)+p?(∑i≥0pi(i+11))g(p,1)=\sum_{i\geq 0}p^i{i+1\choose 1}=(\sum_{i\geq 0}p^i*i)+p*(\sum_{i\geq0}p^i{i+1\choose 1})g(p,1)=i0?pi(1i+1?)=(i0?pi?i)+p?(i0?pi(1i+1?)),于是g(p,1)=g(p,0)1?p=1(1?p)2g(p,1)=\frac{g(p,0)}{1-p}=\frac{1}{(1-p)^2}g(p,1)=1?pg(p,0)?=(1?p)21?
k>1k>1k>1时,g(p,k)=∑i≥0pi(i+1k)=∑i≥k?1pi(i+1k)=p?(∑i≥k?2pi?(i+1k?1))+p?(∑i≥k?1pi(i+1k))g(p,k)=\sum_{i\geq 0}p^i{i+1\choose k}=\sum_{i\geq k-1}p^i{i+1\choose k}=p*(\sum_{i\geq k-2}p^i*{i+1 \choose k-1})+p*(\sum_{i\geq k-1}p^i{i+1\choose k})g(p,k)=i0?pi(ki+1?)=ik?1?pi(ki+1?)=p?(ik?2?pi?(k?1i+1?))+p?(ik?1?pi(ki+1?)),于是g(p,k)=p?g(p,k?1)1?p=pk?1(1?p)k+1(k>1)g(p,k)=\frac{p*g(p,k-1)}{1-p}=\frac{p^{k-1}}{(1-p)^{k+1}}(k>1)g(p,k)=1?pp?g(p,k?1)?=(1?p)k+1pk?1?(k>1)
直接按式子计算即可,时间复杂度O(nk)O(nk)O(nk)

#include <bits/stdc++.h>
#define MOD 998244353using 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(i+1)^k(i+1)k当做了iki^kik来算,大体上是一样的(可以自己推推)。唯一区别是在k=1k=1k=1时,并不需要特判,也就是g(p,k)=pk(1?p)k+1(k&gt;0)g(p,k)=\frac{p^k}{(1-p)^{k+1}}(k&gt;0)g(p,k)=(1?p)k+1pk?(k>0)
为什么输出会撞上呢?问了问dcx,虽然我们推的式子不同,可是都把(i+1)k(i+1)^k(i+1)k当成了iki^kik
最后发现原来的数据是对的,感觉极度尴尬。
自闭了。

扩展

稍微推导一下,发现运用等幂和其实可以做到O(nlog2n)O(nlog^2n)O(nlog2n)的复杂度。代码还没有。