P8967 追寻 | Pursuit of Dream 题解

P8967 追寻 | Pursuit of Dream

很久没做过这种酸爽的推式子题了。

首先可以确定的是,看似每个点的坐标的每个维度都是 \(10^7\) 级别的,实际上有用的点只有 \(k\) 个,剩下点之间的期望都是相同并且可计算的。

对于期望 DP,一般是逆推的方法。考虑设一个 \(f_i\) 表示从第 \(i\) 个点出发到达终点的期望步数,其中特殊地定义 \(f_0\) 表示 \((0,0,\dots,0)\) 这个点。由期望的线性性,这个期望分为三部分:直接到终点的期望、中间发生散入天际的期望。这两部分加和就是当前点的答案。最后的答案显然为 \(f_0\)

直接到达终点

显然前者较为好算,我们先来计算前者,也就是直接到达终点的期望。

对于一个点 \((a_1,a_2,\dots,a_n)\),它到终点 \((d_1,d_2,\dots,d_n)\) 显然需要 \(\sum_{j=1}^n(d_j-a_j)\) 步,把这个值记作 \(s_i\)。注意到这样计算有意义当且仅当 \(\forall d_j\ge a_j\) 时,因为我们只能往前走,于是但凡 \(\exists d_j<a_j\),这个点直接到达终点的期望就是 \(0\)

还有一点需要注意,我们要保证这 \(s_i\) 步都不会散入天际,这个概率是 \((1-p)^{s_i}\)

想要走完这 \(s_i\) 步显然有 \(n^{s_i}\) 种走法,因为每一步都可以走在任意一个维度上。我们接下来需要求出合法的走法数量。注意到这个问题可以转化为多重集的排列数问题,即我们有一个集合 \(S\),其中包含 \(d_1-a_1\)\(x_1\)\(d_2-a_2\)\(x_2\)、……、\(d_n-a_n\)\(x_n\),求 \(S\) 的全排列数。由公式可得,这个全排列数为 \(\dfrac{s_i!}{\prod_{j=1}^n(d_j-a_j)!}\)。也就是一共有这么多种合法的走法。最后我们得到直接到达终点的概率

\[q_i=\cfrac{\cfrac{s_i!}{\prod_{j=1}^n(d_j-a_j)!}}{n^{s_i}}\times(1-p)^{s_i} \]

于是这部分的期望步数就是 \(q_is_i\)

出现散入天际

首先可以确定的是,不能使 \(f_i\) 的式子里面出现 \(f_j\) 之类的东西,那样的话就需要高斯消元,但复杂度我们显然无法承受。

但是注意到,不管从哪里散入天际,这个期望都是恒定的。也就是说,“散入天际之后到达终点” 这一部分的期望和 \(i\) 无关。于是考虑求出这一部分不变量,记作 \(g\)。容易得到

\[g=\sum_{i=1}^k\frac{p_i}pf_i \]

到这一步,\(f_i\) 的表达式还缺一部分,就是从 \(i\) 出发到达散入天际那个点的期望步数。直接求是不好求的,因为我们根本不知道走多少步会散入天际。考虑容斥,分别计算从当前点出发到处乱走然后遇到散入天际的期望,以及从当前点出发先走到终点再到处乱走然后散入天际的期望,二者相减就是答案。

前者的计算是一个很典的结论,如下:

\[\sum_{i=1}^\infty(1-p)^{i-1}\times i\times p=\frac1p \]

用求导可证明。后一部分的计算参考我们上文计算的结果,走到终点的期望步数是 \(q_is_i\),之后的期望步数是 \(q_i\times\dfrac1p=\dfrac{q_i}p\)。所以从点 \(i\) 出发到达散入天际那个点的期望步数就是

\[\frac1p-q_is_i-\frac{q_i}p \]

于是我们得到了 \(f_i\) 的最终表达式:

\[\begin{aligned}f_i&=q_is_i+(1-q_i)g+\frac1p-q_is_i-\frac{q_i}p\\&=(1-q_i)g+(1-q_i)\times\frac1p\\&=(1-q_i)\bigg(g+\frac1p\bigg)\end{aligned} \]

酸爽推式子

发现 \(f_i\) 的这个式子中,\(q_i\)\(p\) 都是好求的,考虑解出 \(g\)

\(f_i\) 代入 \(g=\sum\limits_{i=1}^k\dfrac{p_i}pf_i\) 中得到:

\[\begin{aligned} g&=\sum_{i=1}^k\frac{p_i}p(1-q_i)\bigg(g+\frac1p\bigg)\\ &=g\Bigg(\sum_{i=1}^k\frac{p_i}p(1-q_i)\Bigg)+\frac1p\Bigg(\sum_{i=1}^k\frac{p_i}p(1-q_i)\Bigg) \end{aligned} \]

再整理得:

\[\Bigg(1-\sum_{i=1}^k\frac{p_i}p(1-q_i)\Bigg)g=\frac1p\Bigg(\sum_{i=1}^k\frac{p_i}p(1-q_i)\Bigg) \]

于是我们只需知道 \(p_i,p,q_i\) 这三个量就可以解出 \(g\),而这三个量都是好求的,于是解出 \(g\) 之后代入 \(f\) 的式子中,输出 \(f_0\) 即可。

#include<bits/stdc++.h>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define inv(x) power(x,MOD-2)
using namespace std;

char buf[1<<20],*p1=buf,*p2=buf;
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
using ll=long long;
constexpr int MAXN=105,MAXK=10005,MAXV=1e7+5;
constexpr ll MOD=998244353,inv8=205817851;
int n,k;
ll d[MAXN],a[MAXK][MAXN],p[MAXK],P,invP,s[MAXK],q[MAXK];
ll fac[MAXV];

ll power(ll a,ll b){
	ll res=1;
	for(;b;a=a*a%MOD,b>>=1)if(b&1)res=res*a%MOD;
	return res;
}
void init(){
	fac[0]=1;
	for(int i=1;i<MAXV;i++) fac[i]=fac[i-1]*i%MOD;
}
void add(ll&x,ll y){
	x=(x+y>=MOD?x+y-MOD:x+y);
}

int main(){
	init();
	n=read(),k=read();
	for(int i=1;i<=n;i++) d[i]=read(),s[0]+=d[i];
	for(int i=1;i<=k;i++){
		for(int j=1;j<=n;j++){
			a[i][j]=read();
			if(d[j]<a[i][j]) s[i]=-1;
			else if(~s[i]) s[i]+=d[j]-a[i][j];
		}
		p[i]=inv8*read()%MOD;
		add(P,p[i]);
	}
	invP=inv(P);
	ll res1,res2=0,g;
	for(int i=0;i<=k;i++){
		if(~s[i]){
			q[i]=fac[s[i]]*power((1-P+MOD)%MOD,s[i])%MOD*inv(power(n,s[i]))%MOD;
			for(int j=1;j<=n;j++) q[i]=q[i]*inv(fac[d[j]-a[i][j]])%MOD;
		}
		add(res2,p[i]*invP%MOD*((1-q[i]+MOD)%MOD)%MOD);
	}
	res1=(1-res2+MOD)%MOD;
	res2=res2*invP%MOD;
	g=res2*inv(res1)%MOD;
	printf("%lld\n",(1-q[0]+MOD)%MOD*((g+invP)%MOD)%MOD);
	return 0;
}
posted @ 2025-03-03 20:17  Laoshan_PLUS  阅读(23)  评论(0)    收藏  举报