• 吉首大学校赛 I 滑稽树上滑稽果 (Lucas + 莫队)


    链接:https://ac.nowcoder.com/acm/contest/925/I
    来源:牛客网

    题目描述

    n个不同的滑稽果中,每个滑稽果可取可不取,从所有方案数中选取一种,求选取的方案中滑稽果个数不超过m的概率。(对109+7取模)

    输入描述:

    第一行一个正整数T( T <= 10^5 )

    随后T行每行两个整数n,m ( 0 < m <= n <= 10^5 )

    输出描述:

    T行,每行一个整数表示答案。
    示例1

    输入

    复制
    2
    5 2
    5 1

    输出

    复制
    500000004
    687500005


    题意:要你求取的数量不超过m的数量的概率
    思路:首先因为组合数太大,我们就只能用Lucas 来求
    其次这个数据范围太大,我们肯定不能直接暴力求出组合数
    这里我们把 s(m,n) 设为 从n个中选取至多m个物品的方案数,我们可以得出 s(m,n) = s(m-1,n) + c(m,n)
    我们还可以用杨辉三角得出 s(m,n)= 2 * s(m,n-1)*2-c(m,n-1)
    s(4,8) = c(0,8) + c(1,8) + c(2,8) + c(3,8) + c(4,8)
    s(4,7) = c(0,7) + c(1,7) + c(2,7) + c(3,7) + c(4,7)
    我们可以借由定理:c(m,n)+c(m+1,n) = c(m+1,n+1)
    c(0,8)=c(0,7)
    c(1,8)=c(0,7)+c(1,7)
    c(2,8)=c(1,7)+c(2,7)
    c(3,8)=c(2,7)+c(3,7)
    c(4,8)=c(3,7)+c(4,7)
    
    
    我们把m-n当成一个线段,我们就可以让s(m,n) ->   s(m+1,n),s(m-1,n),s(m,n+1),s(m,n-1);
    我们可以进行O(1)转移,这里我们就好办了,我们用莫队离线排序查询然后进行转移

    #include<bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define P 1000000007
    #define mod 1000000007
    #define N 100010
    #define LL long long
    using namespace std;
    typedef long long ll;
    struct query{int l,r,block,id;} Q[N];
    LL w[N],inv[N],ans[N];
     
    bool cmp(query a,query b)
    {
        if (a.block!=b.block) return a.l<b.l;
        if (a.block&1) return a.r<b.r; return a.r>b.r;
    }
     
    LL C(int r,int l)
    {
        if (r<l) return 0;
        return w[r]*inv[l]%P*inv[r-l]%P;
    }
     
    ll quick_pow(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1) ans=(ans*a)%mod;
            a=(a*a)%mod;
            b=b/2;
        } 
        return ans;
    } 
    int main()
    {
        w[0]=1;w[1]=1;inv[1]=1; inv[0]=1;
        for (int i=2;i<N;i++)
        {
            w[i]=w[i-1]*i%P;
            inv[i]=inv[P%i]*(P-P/i)%P;
        }
        for (int i=2;i<N;i++) inv[i]=inv[i-1]*inv[i]% P;
        int block=sqrt(100000);
        int n;
        cin>>n;
        for (int i=1;i<=n;i++)
        {
            cin>>Q[i].r>>Q[i].l;
            Q[i].id=i;Q[i].block=Q[i].l/block;
        }
        int l=1,r=1;LL t=2;
        sort(Q+1,Q+n+1,cmp);
        for (int i=1;i<=n;i++)
        {
            while(l<Q[i].l)
            {
                t=(t+C(r,l+1))%P;
                l++;
            }
            while (l>Q[i].l)
            {
                l--;
                t=(t-C(r,l+1)+P)%P;
            }
            while (r<Q[i].r)
            {
                r++;
                t=(2*t-C(r-1,l)+P)%P;
            }
            while(r>Q[i].r)
            {
                t=(t+C(r-1,l))*inv[2]%P;
                r--;
            } 
            ll sum=quick_pow((ll)2,Q[i].r); 
            sum=quick_pow(sum,mod-2);
            ans[Q[i].id]=(t*sum)%mod;
            //ans[Q[i].id]=sum;
        }
        for (int i=1;i<=n;i++)cout<<ans[i]<<endl;
        return 0;
    }
    
    
    


  • 相关阅读:
    Windows快捷键使用技巧
    windows 开机启动设置快捷方式
    MySQL如何下载win32的库文件
    C/C++ MySQL API调用
    mysql_error list
    SSL/TLS数字证书各种格式解释
    linux常用命令(持续更新)
    【原创】Huatuo热更框架之手把手部署
    【Linux】使用Google Authenticator 实现ssh登录双因素认证
    如何查看debian dpkg包 的内容?
  • 原文地址:https://www.cnblogs.com/Lis-/p/11073020.html
Copyright © 2020-2023  润新知