loj6300 「CodePlus 2018 3 月赛」博弈论与概率统计

link

 

题意:

A和B玩游戏,每轮A赢的概率为p。现在有T组询问,已知A赢了n轮输了m轮,没有平局,赢一局A得分+1,输一局得分-1,问A得分期望值?

$n+m,T\leq 2.5\times 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。其中需要满足$k\geq \max(m-n,0)$,原因:既要保证之前得分$\leq 0$($y\geq x$),又要保证之后不会出现$\leq 0$($m-y\leq 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}$。

假设$n\ge m$,那么可以列出这样一个式子:

$$\begin{equation}ans=\sum_{k=0}^{m}(C_{n+m}^{n+k}-C_{n+m}^{n+k+1})(n-m+k)\end{equation}$$

一看就可以列项,化简以后得:

$$\begin{equation}ans=(n-m)C_{n+m}^{n}+\sum_{k=0}^{m-1}C_{n+m}^{k}\end{equation}$$

$n\leq m$同理,此时k从m-n开始,化简以后得:

$$\begin{equation}ans=\sum_{k=0}^{n-1}C_{n+m}^k\end{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}(n\sqrt{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\n",ans[i]);
58     return 0;
59 }
View Code

 

posted @ 2018-08-19 15:32  bestfy  阅读(360)  评论(0编辑  收藏