zoukankan      html  css  js  c++  java
  • LOJ6300 BZOJ5283 [CodePlus 2018 3 月赛]博弈论与概率统计

    一道好题!很久以前就想做了,咕到了现在,讲第二遍了才做。

    首先我们观察到$p$是没有用的 因为赢的次数一定 那么每一种合法序列出现的概率均为$p^n*(1-p)^m$ 是均等的 我们可以不看它了

    然后我们可以通过计算所有序列的答案再除以$C_{n+m}^n$就可以了

    然后我们开始进行神奇操作

    赢的话就是+1输的话就是-1 那么我们可以观察到最后的结果就是$n-m-min left (s_i ight )$ 其中s表示前缀和

    那么我们有答案就是$C_{n+m}^n left (n-m ight ) - min left (s_i ight )$ 其中第一项直接解决 我们考虑处理第二项

    第二项我们用一个$f[x]$来表示 最小值为$x$的方案数 这个玩意直接求并不好求 那么我们考虑利用差分性来求

    我们再设$g[x]$表示最小值$<=x$的方案数 于是$f[x]=g[x]-g[x-1]$

    考虑求数组$g$

    我们发现这个数列的转移只有两种 $(x,y)->(x+1,y+1)$ 或者 $(x,y)->(x+1,y-1)$ 分别对应着Alice赢和Bob赢

    如果一个序列的最小值$<=k$那么它一定会有一部分位于$y=k$上/以下 接下来继续思考

    如果我们把第一次接触到$y=k$的点以后的图像翻转 那么最后一个节点的坐标就是$left ( n+m,2*k-n+m ight )$

    这样的话我们就可以得到比较优美的性质 就是Alice赢了$k+m$次 Bob赢了$n-k$次

    那么显然这样的折线应该是有$C_{n+m}^{m+k}$个 于是可以得到$g[x]=C_{n+m}^{m+k}$ 推到$f[x]=C_{n+m}^{m+k}-C_{n+m}^{m+k-1}$

    继续向下推导

    首先发现n>=m 和 n<m是不一样的 因为前者的最小值区间是$left[-m,0 ight]$ 后者是$left[-m,n-m ight]$

    这两类是不一样的于是我们分类讨论

    对于第一种我们如下推导

    $ans=(n-m)C_{n+m}^n-x*f[x]$

    $ans=(n-m)C_{n+m}^n-sum_{x=-m}^0 C_{n+m}^{m+x} - C_{n+m}^{m+x-1}$

    $ans=(n-m)C_{n+m}^n+sum_{x=0}^m C_{n+m}^{m-x} - C_{n+m}^{m-x-1}$

    $ans=(n-m)C_{n+m}^n+sum_{x=0}^m x*C_{n+m}^{m-x} - sum _{x=0}^{m-1} x*C_{n+m}^{m-x-1}$

    $ans=(n-m)C_{n+m}^n+sum_{x=0}^{m-1}C_{n+m}^{m-x-1}$

    $ans=(n-m)C_{n+m}^n +sum_{x=0}^{m-1}C_{n+m}^x $

    对于n<m我在这里留给读者自行推导 (才不是因为我懒

    最后的柿子也很相似

    $ans=sum_{x=0}^{n-1} C_{n+m}^x$

    然后我们就落到了最后一个问题

    组合数前缀和怎么算= =

    这是一个常见问题

    我们有

    $sum_{x=0}^m C_{m+1}^x = sum _{x=0}^{m}(C_n^x + C_n^{x-1})=(2*sum_{x=0}^m C_n^x)-C_n^m$

    详细理解请参照杨辉三角

    然后呢 我们惊奇的发现 特么多组询问!!!

    这个咋整呢

    我们可以利用莫队来做 我们对于组合数前缀和可以$O(1)$转化了 那么 我们就可以愉快的套上莫队美滋滋

    在这里我遇到了一点小问题 就是在初始化的地方 如果id循环到N就是可以过的 循环到T是会T的 具体情况我也不知道

    感觉和底层优化? 或者计算机硬件有关? 这个如果有神仙知道为什么的话请一定联系我!会超级感谢!

    这个题整体思路都很神仙 大概不看的话是完全想不到的 用莫队来做组合数前缀和很久以前也就听说过了 在这里第一次使用到

    还有此题略微卡常 虽然我没遇到 但是前面那个小问题还是卡了很久 看了标程对着才改到 所以这个题还是可以多看看学习一下的

    最后的复杂度是$O((n+m)sqrt(n+m))$

    不清楚为什么大家块大小都取的477 跟风一波。

    代码扔这里了。

    //Love and Freedom.
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #define ll long long
    #define inf 20021225
    #define N 250001
    #define B 477
    #define mdn 1000000007
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0' || ch>'9')    {if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0' && ch<='9')    s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    int ksm(int bs,int mi)
    {
        int ans=1;
        while(mi)
        {
            if(mi&1)    ans=1ll*ans*bs%mdn;
            bs=1ll*bs*bs%mdn; mi>>=1;
        }
        return ans;
    }
    struct node
    {
        int l,r,id;
        node(){}
        node(int _l,int _r,int _id){l=_l,r=_r,id=_id;}
    }k[N],a[N];
    int id[N],fac[N],inv[N],ans,fin[N],T;
    void add(int &x,int y){x=x+y>=mdn?x+y-mdn:x+y;}
    void sub(int &x,int y){x=x-y<0?x-y+mdn:x-y;}
    bool cmp(node a,node b)
    {
        if(id[a.l]==id[b.l])    return a.r<b.r;
        return id[a.l]<id[b.l];
    }
    int C(int n,int m)
    {
        if(n<m)    return 0;
        return 1ll*fac[n]*inv[m]%mdn*inv[n-m]%mdn;
    }
    int invC(int n,int m)
    {
        if(n<m)    return 0;
        return 1ll*inv[n]*fac[m]%mdn*fac[n-m]%mdn;
    }
    void upd(int n,int m,int f)
    {
        if(f==1)    add(ans,ans),sub(ans,C(n,m));
        else if(f==2)    add(ans,C(n-1,m)),ans=1ll*ans*inv[2]%mdn;
        else if(f==3)    add(ans,C(n,m+1));
        else    sub(ans,C(n,m));
    }
    void solve()
    {
        for(int i=1;i<N;i++)    id[i]=i/B+1;
        sort(k+1,k+T+1,cmp); int n=0,m=0; ans=1;
        for(int i=1;i<=T;i++)
        {
            while(n<k[i].l)    upd(n++,m,1);
            while(n>k[i].l)    upd(n--,m,2);
            while(m<k[i].r)    upd(n,m++,3);
            while(m>k[i].r)    upd(n,m--,4);
            add(fin[k[i].id],ans);
        }
    }
    int main()
    {
        T=read(); int p=read();
        fac[0]=1;
        for(int i=1;i<N;i++)    fac[i]=1ll*fac[i-1]*i%mdn;
        inv[N-1]=ksm(fac[N-1],mdn-2);
        for(int i=N-1;i;i--)    inv[i-1]=1ll*inv[i]*i%mdn;
        for(int i=1;i<=T;i++)
        {
            int n=read(),m=read(); a[i].l=n,a[i].r=m;
            if(n>=m)    fin[i]=1ll*(n-m)*C(n+m,n)%mdn,k[i]=node(n+m,m-1,i);
            else    k[i]=node(n+m,n-1,i);
        }
        solve();
        for(int i=1;i<=T;i++)
        {
            int tmp=1ll*fin[i]*invC(a[i].l+a[i].r,a[i].r)%mdn;
            printf("%d
    ",tmp);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    SqLite 框架 GreenDAO
    HttpClient的使用
    android事件分发介绍
    Android常见开发思路
    AndroidStudio学习记录
    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo异常总结
    开源Pull_To_Refresh控件使用
    自定义控件ViewPagae<
    白龙软件商店面试问题整理
    基于anyrtc的sdk实现直播连麦互动
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/11191327.html
Copyright © 2011-2022 走看看