Atcoder题解:Agc056_e

\[也想养老鼠捏 \]

先把当前要解决的点旋转到位置 \(n\),问题不变。求 \(n\) 次即可。

我们先来看两个没有结果的解法。

一就是一

我们先考虑暴力 \(dp\),设 \(dp_{i,mask}\) 表示当前已经安放了 \(i\) 个奶酪,被喂饱的老鼠的集合为 \(mask\) 的概率。容易发现 \(i\) 其实就是 \(mask\)\(1\) 的个数。

然后考虑暴力枚举下一步用哪里的奶酪喂哪里的老鼠,我们发现,在还剩 \(i\) 个老鼠的时候,不套整圈,用 \(x\) 的奶酪贡献到 \(y\) ,一共会经过 \(dist(mask,x,y)\) 次老鼠。而 \(dist(mask,x,y)\) 表示 \(mask\) 中的老鼠已经被喂饱了的情况下,在没喂饱的老鼠中,\(x\) 处的奶酪贡献到 \(y\) 处的老鼠,奶酪会经过没喂饱的老鼠几次。

然后考虑套整圈的情况,其实就是先走到老鼠 \(b\),然后枚举绕多少圈,设还剩下 \(d\) 个老鼠,贡献就是 \(\sum_{n=0}^{\infty}\dfrac{1}{2^{nd}}=\dfrac{1}{1-2^d}\),算起来,贡献就是 \(\dfrac{1}{1-2^d}\sum_{x,y}(a_x\%) 2^{-dist(mask,x,y)}\)

复杂度 \(O(n^22^n)\)

我们发现在任何从 \(dp_{0}\)\(dp_{2^n-1}\)的转移路线中,一定会经过 \(d\)\(2\)\(n\) 的所有情况,也就是,\(\prod_{d=2}^n\dfrac{1}{1-2^d}\) 是每个最终状态都有的系数。可以从转移里提出这一部分,然后在最终答案里乘上就可以了。

我们发现 \(a_x\%\) 也是可以优化的,首先 \(\dfrac{1}{100^{n-1}}\) 可以直接提出来。然后我们发现 \(a_x\) 是整数,所以我们可以改变问题为全环上一共有 \(100\) 个奶酪投放点,第 \(i\) 个位置前面有 \(a_i\) 个,每次在其中等概率随机一个。

\(x\) 改成枚举的奶酪投放的地点,我们就可以优化掉 \(a_x\%\)

这样,我们的问题就简单的变成了,\(\sum_{(\pi,x)} \prod_{i=1}^{n-1}2^{-dist(前 i-1 位的集合,x(i),\pi(i))}\),实际上就是对所有的二元组 \((\pi,x)\) 算贡献。而 \(\pi\) 是其他老鼠被吃掉的顺序的排列,\(x\) 是一个向量,取值 \((1,100)\)

这样我们就可以得到一个 \(O(100\cdot 2^n)\)\(dp\),因为确定 \(x(i)\) 之后,可以递推的确定 \(dist\)。然而,我们发现,这个方法到这里就结束了。

为什么呢?因为 \(dist\) 是和前面的选择直接相关的,因此保持这个思路我们的 \(2^n\) 是不太可能优化下去的。

或许我们抱有一丝期冀,因为我们发现,我们可以把 \(dist\) 转化成贡献,也就是 \(x(i)\)\(\pi(i)\) 的贡献、\(\pi(j)\)\((x(i),\pi(i))\) 的贡献(\(j<i\))。然后我们就可以拆分每个 \(dist\) 的贡献,枚举进行贡献的 \(\pi(j),x(i)\)\(\pi(i)\) 进行组合得到答案。

但是这个梦想也是不现实的,因为首先,\(2\) 的指数加和再求和的方式无法通过平均期望的方式算平均贡献,(当前的 \(\dfrac{1}{2}\) 贡献在哪些状态上是具有后效性的),所以重设 \(dp\) 状态为 xxx 的和或者 xxx 的期望来计算这个东西就不可能了。

然后,对这个贡献进行 \(dp\) 也是行不通的,因为各个贡献不是独立的,必须满足一个偏序关系,也就是如果 \(\pi(j)\)\(\pi(i)\) 贡献,\(\pi(k)\)\(\pi(j)\) 贡献,\(\pi(i)\) 就不能向 \(\pi(k)\) 贡献,所以我们又需要记录哪些位置已经用过了,回到 \(2^n\) 的复杂度。

二就是二

然后考虑另一种做法,破环为链,我们将围绕这个关键词进行一系列尝试。

首先我们一定是在 \(1\)\(n\) 之间把环破开。然后我们考虑这样一件事情:

我们把所有的到达 \(n\) 还没有答案的奶酪都删除掉,映射到在 \(1\) 位置放上一个奶酪。这是什么意思呢?我们钦定所有的绕很多圈的奶酪都仅计算从 \(1\) 到目的地的最后这一段。

这样,我们可以重新计算各个 \(a_i'\) 表示从 \(i\) 出发一个奶酪,喂食一个 \([i,n-1]\) 中的老鼠的概率。

破环成链成功,如果 \(a_i'\) 是个定值,我们就可以 \(dp\) 了。我们只要记录当前的奶酪个数,就可以 \(dp\)

可惜的是,\(a_i'\) 不是定值,甚至于,\(a_i'\) 依旧和前面选择老鼠的详细方案有关。而只要牵扯到详细方案就免不了状压,也就走向了彻底的失败。

为什么 \(a_i'\) 和前面选择老鼠的详细方案有关呢?因为它是和当前点后面有多少个点可以选择有关的,具体而言 \(a_i'=a_i\dfrac{2^k-1}{2^k}\),而 \(a_1\) 就是 \(1-\sum_{i\neq 1}a_i\)。而我们要对于每个位置知道其后面的点的个数,就等价于要知道当前剩下的点的集合。

我们经历了又一次失败,但是希望的火种已经在这里诞生了。

没有三了

然后,让我们分析前两次尝试失败的原因。

我们发现,我们的问题缺少一个转化,在没有问题转化的条件下,其最终会演变成第一个做法所提及的排列和向量的二元组贡献,然后这个问题的答案就必将和详细的选择方案有关,然后就必须保留这个信息(存在后效性)。

以此,我们来尝试第三个做法。我们尝试一开始就把所有的奶酪放下来。

我们先破环成链,然后复制两遍,从第一个开始,设 \(f_{i,j}\) 表示当前来到第 \(i\) 个老鼠,还剩 \(j\) 块奶酪的概率。

然后,我们可以做的第一件事是在这个位置放新的奶酪,枚举个数,注意 \(i+j-1\gt n-1\) 的状态是不合法的,因为我们最多安放 \(n-1\) 个奶酪。

接下来,我们就需要贡献了。我们发现,一个奶酪经过一个老鼠可以有三种可能:

  • 以 0.5 的概率经过老鼠,要求这个奶酪出现在老鼠被喂饱前

  • 以 0.5 的概率被老鼠吃掉

  • 直接通过老鼠,要求这个奶酪出现在老鼠被喂饱后

然后我们可以枚举直接通过的奶酪个数……

发现这里又出现新的问题了。奶酪是否直接通过,也是和奶酪的位置有关的。换句话说,我们虽然表面上解决了老鼠的顺序,却没能解决奶酪的顺序。然后奶酪和老鼠配对,等于我们还是没有解决老鼠的顺序。

但是这里已经给予了我们通向最终正解的道路。我们尝试将这个算法和第二个结合起来……

五在这里

我们来思考二和三的特点。

二的特点是破环成链之后破整为零,只去研究每一块奶酪最后一次经过 \(n\) 之后的结果。弊端是没能省去老鼠的顺序。

三的特点是一开始就不去区分所有的奶酪,按照位置而非时间顺序去放置奶酪,最终统一计算。弊端是没能奶酪的顺序还是对算法存在影响,但是已经把老鼠的顺序转化成了别的东西。同时,我们也没有考虑绕整圈的问题。

\(Cheese,允许访问\)

\(破环成链!\)
\(破整为零!\)
\(破除顺序!\)

\(我将以多项式时间解决此问题\)
\(ご唱和ください 我の名を\)
\(ウルトラマン \mathbb{Z}!\)

我们发现,我们可以先破环成链,然后放下所有的奶酪,然后处理出“它们到 \(n\) 的概率。如果在没到 \(n\) 之前就喂老鼠了,就喂老鼠了吧。

也就是说,我们先处理它们从 \(x\)\(y\) 或者 \(n\) 的链贡献。

接下来是本题的精华所在:

在一个节点的位置,不同时间的奶酪经过,谁留下来、谁付出、谁掠过,都是一样的。

为什么呢?

因为,我们在这一节点可以随便安排所有奶酪的顺序,比如说,本来 \(A\)\(B\) 前面,所以理应是 \(A\) 经过,\(B\) 被吃掉。但是我们完全可以让 \(A\) 被吃掉,\(B\) 经过,后面出现的所有 \(A\) 都变成 \(B\),不会对其他的点的略过造成影响,这是等价的。

所以奶酪的顺序反而无关紧要了。而且,因为如果 \(A\) 略过,\(B\) 被吃掉,\(B\) 换成 \(A\),实际上这个方案是不合法的,我们只是把它当作一个原先的问题的替代就可以了。而原先问题就可以划分成一干等价类,而这其中只有一个是成立的,也就是最终被我们安排在最后一个的吃掉它。我们也只对等价类计算一次贡献即可。

这是至关重要的!

因为我们通过“等价代换两种不同出现时间的方案”,消除了奶酪出现时间对答案的影响!

这就太开心了!现在我们的奶酪和老鼠都变成了按照下标为顺序的,我们只要把老鼠和奶酪配对好,然后随意安排奶酪的顺序。需要注意的是,因为奶酪可能出现在同一个位置,所以还需要在转移的时候做一个多重集。

\(dp_{i,j,k}\) 表示当前 dp 到第 \(i\) 个位置,放置了 \(j\) 块奶酪,一共喂过了 \(k\) 只老鼠。

不过,\(i\) 的维度每次会有两次转移,还是滚动掉好(第一次见到为了正确性不得不滚动的)。

每次先枚举放 \(l\) 块奶酪(注意 \(j+k+l\) 不能超出限制,在放置的时候就先把多重集的 \(\dfrac{1}{l!}\) 乘进去,同时还有 \(a_i^l\),可以预处理一手以保证复杂度。

然后看是喂还是不喂。不喂的话,所有的奶酪都应当经过它,贡献就是 \(2^{-j}\)。喂的话,对于所有 \(2^j\) 种贡献和不贡献的选择,每种所代表的等价类里面恰好有一个是合法的,所以直接进行一次贡献。除了谁都不贡献,这是不可以的,所以要减去一种。对答案的贡献是 \(\dfrac{2^j-1}{2^j}\)

然后我们得到了到达 \(n\) 的结果。接下来呢?还剩下 \(n-k-1\) 个老鼠和奶酪。

我们先让它们都贡献一次 \(n\),从 \(1\) 重新开始。

然后我们发现,我们剩下的奶酪怎么选是独立的了!首先我们用第一种做法中的结论把 \(\prod_{d=2}^{n-k}\dfrac{1}{1-2^d}\) 提出来,然后接下来,剩下的奶酪中的第 \(i\) 个就必须在 \([1,i-1]\) 中选一个,也就是除了最后一个都能选,贡献是 \(\prod_{i=1}^{n-k-1}(1-2^i)\)

然后把奶酪的多重集全排列的 \((n-1)!\) 乘上,我们惊喜的发现,这个做法的复杂度是 \(O(n^5)\),我们解决了这道题!

const ll P=998244353;
inline ll fpow(ll a,ll p){
	if(!p)return 1ll;
	ll res=fpow(a,p>>1);
	if(p&1)return res*res%P*a%P;
	return res*res%P;
}
inline ll inv(ll a){
	return fpow(a,P-2);
}
ll ff=1,n,a[45],x[45],C[45][45],fac[45],ifac[45],pw[45],ipw[45];
ll dp[45][45],pwa[45][45];
inline void init(){
	rep(i,0,40){
		C[i][0]=1;
		rep(j,1,i)C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
	}fac[0]=1,ifac[0]=1,pw[0]=1,ipw[0]=1;
	rp(i,40)fac[i]=fac[i-1]*i%P;
	rp(i,40)ifac[i]=inv(fac[i]);
	rp(i,40)pw[i]=pw[i-1]*2%P;
	rp(i,40)ipw[i]=inv(pw[i]);
	rd(i,n)a[i]=a[i]*inv(100)%P;
}
inline void rotate(int d){
	rd(i,n)x[(i-d-1+n)%n]=a[i];
	rd(i,n){
		pwa[i][0]=1;
		rp(j,n)pwa[i][j]=pwa[i][j-1]*x[i]%P;
	}
}
inline void solve(int cur){
	rotate(cur);
	rep(i,0,n)rep(j,0,n)rep(k,0,n)dp[j][k]=0;
	dp[0][0]=1;
	rep(i,0,n-2){
		per(j,0,n-1){
			rep(k,0,n-1){
				rep(l,1,n-j-k){
					dp[j+l][k]=(dp[j+l][k]+dp[j][k]*pwa[i][l]%P*ifac[l]%P)%P;
				}
			}
		}
		rep(j,0,n-1){
			per(k,0,n-1){
				if(dp[j][k]){
					if(k!=n-1){
						if(j)dp[j-1][k+1]=(dp[j-1][k+1]+dp[j][k]*(1-ipw[j]+P)%P)%P;
						dp[j][k]=dp[j][k]*ipw[j]%P;
					}
				}
			}
		}
	}
	per(j,0,n-1){
		rep(k,0,n-1){
			rep(l,1,n-j-k){
				dp[j+l][k]=(dp[j+l][k]+dp[j][k]*pwa[n-1][l]%P*ifac[l]%P)%P;
			}
		}
	}
	ll ans=0;
	rep(k,0,n-1){
		if(dp[n-k-1][k]){
			ll res=1;
			rep(x,1,n-1-k){
				res=(1-ipw[x]+P)%P*inv((1-ipw[x+1]+P))%P*res%P;
			}
			ans=(ans+dp[n-k-1][k]*ipw[n-1-k]%P*fac[n-1]%P*res%P)%P;
		}
	}cout<<ans<<" ";
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	rd(i,n)cin>>a[i];
	init();
	rd(i,n)solve(i);
	return 0;
}
//Crayan_r
posted @ 2023-04-23 20:29  jucason_xu  阅读(28)  评论(0编辑  收藏  举报