ARC132E题解

简要题意

n 个方块,每个方块有一个初始状态可能为左右或者空。每次操作随机选择一个空进行操作。每次操作可以向左或者向右走一直到下一个空或者走出边界,走到的每个格子会变成左或者右,这取决于移动方向。

求无法操作时方格为左的期望数。

数据范围:n105

题解

首先看到这个操作我们可以把每一段方格看成一个整体,以空为分界线,然后最自然的思路就是对于每一个整体考虑对答案的贡献。

然后大概说一下我的想法。就是对于第 i 个连续段考虑它被更新过和没被更新过两种状态下的贡献。

  • 对于没被更新的情况,需要满足对于它左边的空都向左走,右边的空都向右走,贡献就是原始区间中左方格的个数。
  • 对于被更新的情况,如果最后被左边向右的覆盖则无贡献,否则就贡献区间长度。

然后经过一番推导你会发现,第二种情况求解的复杂度似乎是 O(n) 的,然后就炸了。所以我们需要优化一下思路。

我们可以从最终状态入手。

考虑最终的方格状态一定是左边一段左方格,右边一段右方格,然后中间的一段是原始状态。原因显然。

所以我们只用讨论最后哪一段没有被覆盖过,直接枚举是 O(n) 的。然后对于每一段,它左边的格子都有贡献,它本身的贡献是它原始贡献,它的右边没有贡献。于是我们只用算出它的系数就能求解问题了。

于是我们可以设计一个状态 fn 表示让 n 个连续段都向左且不影响右边放个的状态的概率,考虑从 fn1 转移。因为只有最后一个空选择向右走才会不合法,于是就把第 n1选择方法解放了,所以转移就是 fn=fn1×(112n2)

然后对于枚举段的右边和左边其实是等价的,所以这段的答案就是 fleft×fright×(cntleft+originali)

其中 cnt 是前缀个数,original 是当前段原始左方格数。

代码

signed main(){
	for(int i = 1; i <= n; ++i)
		if(a[i] == '<')++cnt;
		else if(a[i] == '.')s[++tot] = i, c[tot] = cnt;
	c[++tot] = cnt; f[1] = 1;
	for(int i = 2; i <= tot; ++i)f[i] = 1ll * f[i - 1] * (p + 1 - qmi(2 * i - 2, p - 2)) % p;
	for(int i = 1; i <= tot; ++i)ans = (0ll + ans + 1ll * f[i] * f[tot - i + 1] % p * (c[i] - c[i - 1] + s[i - 1])) % p;
}
posted @   Lyrella  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示