ARC132E

发布时间 2023-06-08 21:58:10作者: CelticOIer

https://www.luogu.com.cn/problem/AT_arc132_e

由于一旦走到头那么这一个后缀/前缀就一定是对应的颜色,所以最终答案形如一段左脚印,一段保留原来的,一段右脚印。

保留原来的段一定是在两个洞之间的一段完整段,考虑枚举这个段,左脚印的数量是确定的,转化成算概率的问题。

这实际上等价于这样一个问题:给 \(n\) 个点,每次随机一个点向左/向右,问一直触碰不到右边界的概率。

考虑触碰到右边界一定是选择了一个最右边的点并且向右走,那么就可以列出 dp 式:

\[f_i=\sum_{j=1}^{i} \cfrac{1}{2i}f_{j-1} \]

其中 \(j\) 表示的是最靠右的点出现在排列中的位置,每个位置概率相等都是 \(\cfrac{1}{i}\),再乘上在这里一定向左,概率 \(\cfrac{1}{2}\)

前缀和优化,复杂度 \(O(n)\)

#include<bits/stdc++.h>
#define N 301001
#define MAX 2001
using namespace std; 
typedef long long ll;
typedef double db;
const ll inf=1e9,mod=998244353,inv2=(mod+1)/2;
inline void read(ll &ret)
{
	ret=0;char c=getchar();bool pd=false;
	while(!isdigit(c)){pd|=c=='-';c=getchar();}
	while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();}
	ret=pd?-ret:ret;
	return;
}
ll n,sum[N],pre[N],dp[N],st[N],inv[N],ans;
char s[N];
signed main()
{
	read(n);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
		pre[i]=pre[i-1]+(s[i]=='.');
	ll las=0;
	dp[0]=1;
	st[0]=1;
	inv[1]=1;
	for(int i=2;i<N;i++)
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1;i<N;i++)
		dp[i]=st[i-1]*inv2%mod*inv[i]%mod,st[i]=(st[i-1]+dp[i])%mod;
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+(s[i]=='<');
		if(s[i]=='.')
		{
			if(las)
				ans+=dp[pre[las]]*(las-1+sum[i]-sum[las]+1)%mod*dp[pre[n]-pre[i-1]]%mod;
			else
				ans+=dp[pre[n]-pre[i-1]]*sum[i]%mod;
			las=i;
		}
	}
	if(!las)
		ans=sum[n];
	else
		ans+=(sum[n]-sum[las]+las)*dp[pre[las]]%mod;
	printf("%lld\n",(ans%mod+mod)%mod);
	exit(0);
}