逃亡 解题报告

逃亡

题意

数轴上有 \(m\) 个整型随机变量,每个单位时间内,每个随机变量会等概率增大或减小 \(1\),问 \(n\) 个单位时间内,期望有多少个整数至少被经过一次。

数据范围

设测试点编号为\(k\)

测试点 \(n\) \(m\)
\(1 \sim 4\) \(\le 5000\) \(=1\)
\(5 \sim 6\) \(=\lfloor (\log_{1.04}k)^4\rfloor\) \(=k-4\)
\(7 \sim 10\) \(=\lfloor (\log_{1.04}k)^4\rfloor\) \(=1\)
\(11 \sim 20\) \(\le 100000\) \(\le 20\)

考场打表一时爽,放屁一点都不爽,这个题压根没拿到分数...

先考虑\(m=1,n=1e7\)的那些分

首先,题目可以被转化成求每个整数位置被经过的概率,常见的化期望为概率的方法。

然后把被经过分成两类,一类是最后停在这个点,一类是经过了这个点,这样经过每某个点可以从其他点的停在某个点的概率求过来。

先考虑一个变量从\(0\)开始停在数轴右边位置\(i\)的概率\(E(i)\),首先这个停住的位置必须和\(n\)奇偶性相同,而每一次可以走右边或左边,那么需要走右边的次数为\(\frac{n+i}{2}\),于是可以根据组合意义得到

\[E(i)=[i\equiv n\pmod 2]\frac{1}{2^n}\binom{n}{\frac{n+i}{2}} \]

然后设\(p_i\)为经过\(i\)的概率,那么有两种情况,一种是越过了\(i\)停在\(i\)的右边,一种是停在\(i\)的左边,稍微研究一下我们可以发现,这两种情况的答案是一样的。可以这么理解,更换原点为\(i\),然后重新跑,显然两边有对称,那么\(p_i\)

\[p_i=E_i+2\sum_{j>i}p_j \]

推广到多个起点的情况是差不多的,仍然是求每个点的概率,相交的地方算一下不经过的概率减一下就可以了,复杂度\(O(nm^2)\)


Code:

#include <cstdio>
#include <algorithm>
const int mod=998244353;
#define add(a,b) (a+b>=mod?a+b-mod:a+b)
#define mul(a,b) (1ll*(a)*(b)%mod)
const int N=12000000;
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int n,m,pos[30],fac[N],inv[N],E[N],p[N];
#define C(m,n) mul(fac[m],mul(inv[n],inv[(m)-(n)]))
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d",pos+i);
	fac[0]=1;for(int i=1;i<=n;i++) fac[i]=mul(fac[i-1],i);
	inv[n]=qp(fac[n],mod-2);
	for(int i=n-1;~i;i--) inv[i]=mul(inv[i+1],i+1);
	int p2=qp(qp(2,n),mod-2);
	for(int i=n&1;i<=n;i+=2) E[i]=mul(C(n,(n+i)/2),p2);
	for(int i=n;i>=0;i--) p[i]=add(E[i],add(p[i+1],E[i+1]));
	std::sort(pos+1,pos+1+m);
	int l=pos[1]-n,r=pos[m]+n,ans=0;
	for(int i=l;i<=r;i++)
    {
        int pn=1;
        for(int j=1;j<=m;j++)
        {
            int d=abs(pos[j]-i);
            if(d<=n) pn=mul(pn,add(1,mod-p[d]));
        }
        ans=add(ans,add(1,mod-pn));
    }
    printf("%d\n",ans);
	return 0;
}

2019.1.14

posted @ 2019-01-14 19:40  露迭月  阅读(139)  评论(0)    收藏  举报