逃亡
题意
数轴上有 (m) 个整型随机变量,每个单位时间内,每个随机变量会等概率增大或减小 (1),问 (n) 个单位时间内,期望有多少个整数至少被经过一次。
数据范围
设测试点编号为(k)
测试点 | (n) | (m) |
---|---|---|
(1 sim 4) | (le 5000) | (=1) |
(5 sim 6) | (=lfloor (log_{1.04}k)^4 floor) | (=k-4) |
(7 sim 10) | (=lfloor (log_{1.04}k)^4 floor) | (=1) |
(11 sim 20) | (le 100000) | (le 20) |
考场打表一时爽,放屁一点都不爽,这个题压根没拿到分数...
先考虑(m=1,n=1e7)的那些分
首先,题目可以被转化成求每个整数位置被经过的概率,常见的化期望为概率的方法。
然后把被经过分成两类,一类是最后停在这个点,一类是经过了这个点,这样经过每某个点可以从其他点的停在某个点的概率求过来。
先考虑一个变量从(0)开始停在数轴右边位置(i)的概率(E(i)),首先这个停住的位置必须和(n)奇偶性相同,而每一次可以走右边或左边,那么需要走右边的次数为(frac{n+i}{2}),于是可以根据组合意义得到
[E(i)=[iequiv npmod 2]frac{1}{2^n}inom{n}{frac{n+i}{2}}
]
然后设(p_i)为经过(i)的概率,那么有两种情况,一种是越过了(i)停在(i)的右边,一种是停在(i)的左边,稍微研究一下我们可以发现,这两种情况的答案是一样的。可以这么理解,更换原点为(i),然后重新跑,显然两边有对称,那么(p_i)有
[p_i=E_i+2sum_{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
",ans);
return 0;
}
2019.1.14