[hdu7069]Into the woods

考虑将坐标轴旋转45°,即将$(x,y)$变成$(x+y,x-y)$,显然有$|x|+|y|=\max(|x+y|,|x-y|)$

换言之,从新坐标系来看,问题即等价于——初始在$(0,0)$,每一次两维坐标(分别)随机$\pm 1$,求$n$次中到原点的切比雪夫距离(即$\max(|x|,|y|)$)最大值的期望

令$X$为最远距离,问题即求$E(X)=\sum_{i=1}^{n}P(X\ge i)=n-\sum_{i=1}^{n}P(X<i)$

考虑$P(X<i)$,即要求两维坐标绝对值恒小于$i$,不难发现两维独立且相同(指操作),因此令$p_{i}$为其中一维满足此条件的概率,显然$P(X<i)=p_{i}^{2}$

考虑$p_{i}$的组合意义,即求有多少条从$(0,0)$出发到$(n,j)$($j$为任意$|j|<i$的整数)的路径,其中每一步可以移动到$(x+1,y\pm 1)$,且整条路径与$y=\pm i$都无交(再将其除以$2^{n}$即为$p_{i}$)

枚举向上的步数$x$,则$j=2x-n$(要求$|j|<i$),并考虑容斥——

总路径数显然为${n\choose x}$,并要减去与两者有交的路径数

定义一条路径的交点序列,为将其与两者的交点依次记录(0表示与$y=i$有交,1表示与$y=-i$有交),并将该序列相同的相邻项合并,得到的01交替出现的序列

令$f(S)$为交点序列存在前缀$S$的路径数,考虑$f(0)+f(1)-f(01)-f(10)+f(010)+f(101)-...$对每一条路径的贡献,对其交点序列的长度奇偶性分类讨论可以发现都为1

换言之,要减去的值即为该式,另外根据对称性其也为$2(f(0)-f(10)+f(010)-f(1010)...)$(这里的对称性其实是指$j$和$-j$时对称)

显然$f(S)$中的$S$由$|S|$决定,不妨枚举$l=|S|$,贡献系数为$2\cdot (-1)^{l}$,并考虑此时的$f(S)$

类似于卡特兰数的推导,考虑一条对$f(S)$有贡献的路径,将其第一次与$y=i$交点之前的部分以$y=i$为对称轴翻转,将之后其第一次与$y=-i$交点之前的部分以$y=-i$为对称轴翻转,将之后其第一次与$y=i$交点之前的部分以$y=i$为对称轴翻转……(重复$l$次)

(另外,这是以0为开头的$S$,以1为开头的$S$应该要先取$y=-i$再取$y=i$)

由此,即得到了一条以$(0,2il)$为起点的路径(终点仍为$(n,j)$)

另一方面,对于一条以$(0,2il)$为起点的路径,考虑上述过程的逆过程,不难发现总有交点(注意最后一次以一定是以$y=i$为对称轴翻转),因此同样可以得到一条对$f(S)$有贡献的路径

两者一一对应,因此不妨对后者计数,显然即为${n\choose \frac{j-2il+n}{2}}={n\choose x-il}$

综上,路径数为${n\choose x}+2\sum_{l\ge 1}(-1)^{l}{n\choose x-il}$

考虑$x$的范围,由$|j|<i$不难解得为$\lfloor\frac{n-i}{2}\rfloor<x<\lceil\frac{n+i}{2}\rceil$,记$L=\lfloor\frac{n-i}{2}\rfloor+1,R=\lceil\frac{n+i}{2}\rceil-1$,那么即可得到$2^{n}p_{i}=\sum_{x=L}^{R}\left({n\choose x}+2\sum_{l\ge 1}(-1)^{l}{n\choose x-il}\right)$

将其展开并调换后者的枚举顺序,即$\sum_{x=L}^{R}{n\choose x}+2\sum_{l\ge 1}(-1)^{l}\sum_{x=L}^{R}{n\choose x-il}$

注意到$x$的枚举都是形如${n\choose i}$的一个区间,可以$o(1)$计算,另外显然有$il\le R$的限制,即$l$的范围为$o(\frac{n}{i})$,因此直接再在外层枚举$I$,根据调和级数复杂度为$o(n\log n)$

接下来,由最前面的分析,答案即$n-\sum_{i=1}^{n}p_{i}^{2}$,直接计算即可

综上,总复杂度为$o(n\log n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1000005
 4 #define ll long long
 5 int t,n,mod,Inv,ans,fac[N],inv[N],sum[N];
 6 int c(int n,int m){
 7     return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
 8 }
 9 int main(){
10     scanf("%d",&t);
11     while (t--){
12         scanf("%d%d",&n,&mod);
13         Inv=fac[0]=inv[0]=inv[1]=sum[0]=1,ans=n;
14         for(int i=0;i<n;i++)Inv=(ll)(mod+1)*Inv/2%mod;
15         for(int i=1;i<=n;i++)fac[i]=(ll)fac[i-1]*i%mod;
16         for(int i=2;i<=n;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
17         for(int i=1;i<=n;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
18         for(int i=1;i<=n;i++)sum[i]=(sum[i-1]+c(n,i))%mod;
19         for(int i=1;i<=n;i++){
20             int L=(n-i>>1),R=(n+i-1>>1),s=(sum[R]-sum[L]+mod)%mod;
21             for(int l=1;i*l<=R;l++){
22                 int ss=sum[R-i*l];
23                 if (L-i*l>=0)ss=(ss-sum[L-i*l]+mod)%mod;
24                 ss=2*ss%mod;
25                 if (l&1)s=(s-ss+mod)%mod;
26                 else s=(s+ss)%mod;
27             }
28             s=(ll)s*Inv%mod;
29             ans=(ans-(ll)s*s%mod+mod)%mod;
30         }
31         printf("%d\n",ans);
32     }
33     return 0;
34 }
View Code

 

posted @ 2021-08-19 10:29  PYWBKTDA  阅读(323)  评论(0编辑  收藏  举报