P8967 追寻 | Pursuit of Dream 题解
题解
为便于表述,下文称第 \(i\) 个可以散入天际到的点为第 \(i\) 天际点,特别的,起点为第 \(0\) 天际点,\(P=\sum p_i\)
看到恐怖的 \(\sum d_i \le 10^7\) 就知道不能所有点都讨论了。考虑设 \(dp_i\) 表示第 \(i\) 天际点到终点的期望步数,我们把贡献拆开,先只计算天际点到终点不经过散入天际的期望步数。
不散入天际的期望
假设现在在算第 \(i\) 天际点的期望步数,首先注意到步数一定是:
\[\sum_{j=1}^{n} d_{j}-a_{i,j}
\]
所以只用算出概率然后乘起来算贡献即可,我们令 \(s_i\) 等于到终点的步数。
那么可以转化问题为有 \(s_i\) 个球,把它们放入 \(n\) 个盒子中(每一步都有 \(n\) 种选择),求第 \(j\) 个盒子刚好有 \(d_j-a_{i,j}\) 个球的概率,于是这就是 lmx 小学二年级就会的概率期望入门了,答案显然就是(\((1-P)^{s_i}\) 表示 \(s_i\) 步不散入天际的概率):
\[\frac{s_i!}{\prod_{j=1}^{n}(d_j-a_{i,j})!\times n^{s_i}} \times (1-P)^{s_i}
\]
然后我们把这个答案用 \(q\) 数组存起来,特别的,当有任意 \(d_j < a_{i,j}\) 时,\(q_i=0\)。
引入散入天际
为避免 \(dp_i\) 的转移式中出现其他 dp 值,考虑设 \(g\) 表示散入天际后的期望步数,那么显然:
\[g=\sum_{i=1}^{k}\frac{p_i}{P}dp_i
\]
然后第 \(i\) 天际点乱走直到散入天际的期望就是 \(\frac{1}{P}\)。但有可能走到一半走到终点了,应该减掉,走到终点的期望步数为 \(q_is_i\),而走到终点后散入天际的期望为 \(q_i\frac{1}{P}\),于是最后从第 \(i\) 天际点出发直到散入天际的期望就是:
\[\frac{1}{P}-q_i*\left(\frac{1}{P}+s_i\right)
\]
于是有
\[dp_i=q_is_i+\left(1-q_i\right)g+\frac{1}{P}-q_i*\left(\frac{1}{P}+s_i\right)
\]
然后来解 \(g\),代入有:
\[g=\sum_{i=1}^{k}\frac{p_i}{P}\times\left (q_is_i+\left (1-q_i\right )g+\frac{1}{P}-q_i*\left (\frac{1}{P}+s_i\right )\right )
\]
移项整理得:
\[P\left (1+\sum_{i=1}^k\frac{p_i}{P}\left (q_i-1\right )\right )g=\sum_{i=1}^k\frac{p_i}{P}\left (1-q_i\right )
\]
也就是:
\[g=\frac{\sum_{i=1}^k\frac{p_i}{P}\left (1-q_i\right )}{P\left (1+\sum_{i=1}^k\frac{p_i}{P}\left (q_i-1\right )\right )}
\]
然后答案(\(dp_0\))就是:
\[q_0 s_0+\left(1-q_0\right)g+\frac{1}{P}-q_0*\left(\frac{1}{P}+s_0\right)
\]
实际代码中不需要 \(dp\) 数组。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,k,d[10010],a[10010][110],x[10010],fac[10010000],p[10010],q[10010],s[10010],fl[10010],P,g;
int qpow(int x,int y){
int aaa=1;
while(y){
if(y&1){
aaa=aaa*x%mod;
}
x=x*x%mod;
y>>=1;
}
return aaa;
}
signed main(){
fac[0]=1;
for(int i=1;i<=10000000;i++){
fac[i]=fac[i-1]*i%mod;
}
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>d[i];
s[0]=(s[0]+d[i])%mod;
}
for(int i=1;i<=k;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]>d[j]){
fl[i]=1;
}
s[i]=(s[i]+d[j]-a[i][j])%mod;
}
cin>>p[i];
p[i]=p[i]*qpow(1e8,mod-2)%mod;
P=(P+p[i])%mod;
}
for(int i=0;i<=k;i++){
if(fl[i]){
q[i]=0;
continue;
}
int su=1;
for(int j=1;j<=n;j++){
su=su*fac[((d[j]-a[i][j])%mod+mod)%mod]%mod;
}
q[i]=fac[s[i]]*qpow(su*qpow(n,s[i])%mod,mod-2)%mod*qpow((1-P+mod)%mod,s[i])%mod;
}
int zuo=1,you=0;
for(int i=1;i<=k;i++){
zuo=(zuo+p[i]*qpow(P,mod-2)%mod*(q[i]-1)%mod)%mod;
you=(you+p[i]*qpow(P,mod-2)%mod*(((qpow(P,mod-2)-qpow(P,mod-2)*q[i]%mod+mod)%mod)%mod)%mod)%mod;
}
g=you*qpow(zuo,mod-2)%mod;
cout<<(((1-q[0])%mod+mod)%mod*((g+qpow(P,mod-2))%mod)%mod+mod)%mod;
return 0;
}

浙公网安备 33010602011771号