洛谷4260:博弈論與概率統計(組合數學+莫隊/分塊)
阿新 • • 發佈:2019-01-23
題面
題意:小L在玩遊戲,贏了n場,輸了m場
贏一場得1分,輸一場扣1分
若當前為0分,則不會扣
問期望得分
前置技能
有一個n個1和m個-1的序列,求字首和最小值≥0的方案數
考慮不合法的
找到第一個和為-1的字首
將其1與-1翻轉
得到一個有個1和個-1的序列
恰好與不合法的方案一一對應
類比得字首和最小值恰好為的方案數為
考慮n≥m
字首和最小值為i貢獻為n-m+i
經過一輪畫柿子,錯位相減
答案為
設
由可推出和
故可用莫隊或分塊優化
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const LL p=1e9+7;
const int N=600300,nn=550;
int T,Violet;
LL jc[N],Ijc[N],I[N],ans[N],now=1;
int n[N],m[N];
int L=1,R;
struct yy
{
int l,r,num;
}f[N];
bool cmp(yy x ,yy y)
{
if((x.l/nn)==(y.l/nn))
return x.r<y.r;
return (x.l/nn)<(y.l/nn);
}
LL C(int x,int y)
{
return jc[x]*Ijc[y]%p*Ijc[x-y]%p;
}
LL IC(int x,int y)
{
return Ijc[x]*jc[y]%p*jc[x-y]%p;
}
int main()
{
I[1]=jc[0]=Ijc[0]=1;
for(int i=2;i<N;i++)
I[i]=I[p%i]*(p-p/i)%p;
for(int i=1;i<N;i++)
jc[i]=jc[i-1]*i%p,Ijc[i]=Ijc[i-1]*I[i]%p;
cin>>T>>Violet;
for(int i=1;i<=T;i++)
{
f[i].num=i;
scanf("%d%d",&n[i],&m[i]);
f[i].l=n[i]+m[i];
if(n[i]<m[i])
f[i].r=n[i]-1;
else
f[i].r=m[i]-1;
}
sort(f+1,f+T+1,cmp);
for(int i=1;i<=T;i++)
{
int l=f[i].l,r=f[i].r;
while(L<l)
now=(now+now-C(L,R)+p)%p,L++;
while(L>l)
now=(now+C(L-1,R))%p*I[2]%p,L--;
while(R<r)
now=(now+C(L,R+1))%p,R++;
while(R>r)
now=(now-C(L,R)+p)%p,R--;
ans[f[i].num]=now;
}
for(int i=1;i<=T;i++)
if(n[i]<m[i])
printf("%lld\n",ans[i]*IC(n[i]+m[i],n[i])%p);
else
printf("%lld\n",(n[i]-m[i]+ans[i]*IC(n[i]+m[i],n[i])%p)%p);
return 0;
}