题意:
A和B玩游戏,每轮A赢的概率为p。现在有T组询问,已知A赢了n轮输了m轮,没有平局,赢一局A得分+1,输一局得分-1,问A得分期望值?
$n+m,Tleq 2.5 imes 10^5.$
题解:
首先p并没有用。我们需要的是计算所有可能局面A的得分和,最后除以$C_{n+m}^{n}$。
发现得分不小于0非常奇怪,转化一下,考虑设最后一个为0的状态:A赢x次,输y次。那么得分为(n-x)-(m-y)=n-m+y-x。令k=y-x,则y=k+x。其中需要满足$kgeq max(m-n,0)$,原因:既要保证之前得分$leq 0$($ygeq x$),又要保证之后不会出现$leq 0$($m-yleq n-x$)。
(x,y)抽象成平面上的点。整个游戏相当于一条从(0,0)到(n,m)的路径,A赢横坐标+1,A输纵坐标+1,它的得分应该是路径上y-x最大的点的y-x+n-m(最后一个0的状态肯定是在那里取到)。
直接统计得分不那么容易。考虑对于某一个k计算经过直线y=x+k的路径条数$S_k$,那么它们的分数肯定$geq k+n-m$。$S_k-S_{k-1}$就是分数恰好为k+n-m的路径条数。如何计算$S_k$?将(0,0)到路径和y=x+k的第一个交点这部分沿y=x+k翻转,那么等价于计算(-k,k)到(n,m)的路径条数,方案数为$C_{n+m}^{n+k}$。
假设$nge m$,那么可以列出这样一个式子:
$$egin{equation}ans=sum_{k=0}^{m}(C_{n+m}^{n+k}-C_{n+m}^{n+k+1})(n-m+k)end{equation}$$
一看就可以列项,化简以后得:
$$egin{equation}ans=(n-m)C_{n+m}^{n}+sum_{k=0}^{m-1}C_{n+m}^{k}end{equation}$$
$nleq m$同理,此时k从m-n开始,化简以后得:
$$egin{equation}ans=sum_{k=0}^{n-1}C_{n+m}^kend{equation}$$
于是我们只需处理$sum_{k=0}^{n}C_n^k$。设为$F(n,k)$,注意到$C_n^m=C_{n-1}^m+C_{n-1}^{m-1}$,所以$F(n+1,k)=2F(n,k)-C_n^k$;同时$F(n,k+1)=F(n,k)+C_n^{k+1}$。
发现每次n±1/k±1的时候都可以快速维护F(n,k),可以莫队维护(或者分块预处理组合数)。
并不是一定要长得像区间的东西才能用莫队维护。二维的且每次行列变化1后的结果能快速得到的量,也可以抽象成莫队问题。(听说莫队常数比分块来得小)
复杂度$mathcal{O}(nsqrt{n})$。(理解了我半天)
code:
(bzoj卡常并不能过)
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 #define per(i,x,y) for (int i=(x);i>=(y);i--) 4 #define ll long long 5 #define inf 1000000001 6 #define y1 y1___ 7 using namespace std; 8 char gc(){ 9 static char buf[100000],*p1=buf,*p2=buf; 10 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 11 } 12 //#define gc getchar 13 ll read(){ 14 char ch=gc();ll x=0;int op=1; 15 for (;!isdigit(ch);ch=gc()) if (ch=='-') op=-1; 16 for (;isdigit(ch);ch=gc()) x=(x<<1)+(x<<3)+ch-'0'; 17 return x*op; 18 } 19 #define N 250005 20 #define mod 1000000007 21 #define inv2 500000004 22 int Q,fac[N],inv[N],ans[N]; 23 struct ask{int n,m,l,r,id,bl;}q[N]; 24 int ksm(int x,int p){ 25 int ret=1; 26 for (;p;p>>=1,x=(ll)x*x%mod) if (p&1) ret=(ll)ret*x%mod; 27 return ret; 28 } 29 void init(int n){ 30 fac[0]=1; 31 rep (i,1,n) fac[i]=(ll)fac[i-1]*i%mod; 32 inv[n]=ksm(fac[n],mod-2); 33 per (i,n-1,0) inv[i]=(ll)inv[i+1]*(i+1)%mod; 34 } 35 bool cmp(ask x,ask y){return x.bl<y.bl||x.bl==y.bl&&x.r<y.r;} 36 #define C(n,m) (n>=m?(ll)fac[n]*inv[m]%mod*inv[(n)-(m)]%mod:0) 37 #define invC(n,m) ((ll)fac[m]*fac[(n)-(m)]%mod*inv[n]%mod) 38 void upd(ll &x,int y){x+=y;x-=x>=mod?mod:0;} 39 int main(){ 40 init(250000); 41 Q=read();read();int blo=sqrt(Q); 42 rep (i,1,Q){ 43 q[i].n=read(),q[i].m=read(); 44 q[i].id=i; 45 q[i].l=q[i].n+q[i].m;q[i].r=min(q[i].n,q[i].m)-1; 46 q[i].bl=(q[i].l-1)/blo+1; 47 } 48 sort(&q[1],&q[Q+1],cmp); 49 int l=0,r=0;ll now=1; 50 rep (i,1,Q){ 51 while (l>q[i].l) l--,upd(now,C(l,r)),now=(ll)now*inv2%mod; 52 while (r<q[i].r) r++,upd(now,C(l,r)); 53 while (l<q[i].l) upd(now,now),upd(now,mod-C(l,r)),l++; 54 while (r>q[i].r) upd(now,mod-C(l,r)),r--; 55 ans[q[i].id]=(max(q[i].n-q[i].m,0)+now*invC(q[i].l,q[i].n))%mod; 56 } 57 rep (i,1,Q) printf("%d ",ans[i]); 58 return 0; 59 }