• sum(莫队+数学)


    OvO

    • 可以看出,从\((n,m)\)的状态转移到\((n+1,m)\),\((n,m+1)\),\((n-1,m)\),\((n,m-1)\)都是比较容易的,可以直接\(O(1)\)转移。
      有以下式子:

    \[S_{n}^{m+1}=S_{n}^{m}+C_{n}^{m+1} \]

    \[S_{n}^{m-1}=S_{n}^{m}-C_{n}^{m} \]

    \[S_{n+1}^{m}=S_{n}^{m}*2-C_{n}^{m} \]

    \[S_{n-1}^{m}=\frac{S_{n}^{m}+C_{n-1}^{m}}{2} \]

    然后根据这些式子加上莫队的板子即可。
    \(r\)设为\(n\),\(l\)看作\(m\),然后在指针移动的时候,按照上面式子转移即可。
    记得用线性求逆元,另外在求组合数的时候记得要判\(a<b:return 0\)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define int long long
    using namespace std;
    const int maxn=1e5+1,maxnn=1e5+1;
    const int mod=1e9+7;
    int ID;
    int belong[maxn];
    int ans[maxn];
    int fac[maxn];
    int n,Max=0;
    int inv[maxnn],invv[maxn];
    struct E{int l,r,id;}q[maxn];
    void Pre(){
        fac[1]=1;
        for(int i=2;i<=1e5;i++)fac[i]=fac[i-1]*i%mod;
        inv[1]=invv[1]=inv[0]=invv[0]=1;
        for(int i=2;i<=1e5;i++)invv[i]=mod-mod/i*invv[mod%i]%mod,inv[i]=inv[i-1]*invv[i]%mod;
    }
    int Fp(int b,int p){
        int res=1;
        while(p){
            if(p&1)res=res*b%mod;
            p>>=1;b=b*b%mod;
        }return res;
    } 
    int Comb(int a,int b){
        if(a<b)return 0;
        if(a==b||b==0)return 1;
        return (fac[a]*inv[b]%mod)*inv[a-b]%mod;
    }
    bool Cmp(E a,E b){
        return (belong[a.l]^belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
    }
    signed main(){
        freopen("sum.in","r",stdin);
        freopen("sum.out","w",stdout);
        scanf("%lld",&ID);
        scanf("%lld",&n);
        Pre();
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&q[i].r,&q[i].l);
            q[i].id=i; 
            Max=max(Max,q[i].r);
        }  
        int sz=sqrt(Max);
        int bnum=ceil((double)n/sz);
        for(int i=1;i<=bnum;++i){
            for(int j=(i-1)*sz+1;j<=i*sz;++j){
                belong[j]=i;        
            }
        }
        sort(q+1,q+n+1,Cmp);
        int ANS=2;
        int l=1,r=1;   
        for(int i=1;i<=n;i++){ 
            int ql=q[i].l,qr=q[i].r;   
            while(l<ql){ANS=(ANS+Comb(r,++l))%mod;}
            while(l>ql){ANS=(ANS-Comb(r,l--)+mod)%mod;}
            while(r<qr){ANS=(ANS*2%mod-Comb(r++,l)+mod)%mod;}
            while(r>qr){ANS=((ANS+Comb(--r,l)))%mod*invv[2]%mod;}
            ans[q[i].id]=ANS%mod;
        }for(int i=1;i<=n;i++){
            printf("%lld\n",ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    html的基本框架和常用标签
    防火墙
    Zenmap
    每日一招:熟练掌握变盘方向
    每日一招:赚钱最快的选股策略
    操盘策略:黄金做单时间
    每日一招:坚守六大方式选出优质股
    如何保卫你的牛市胜利果实?
    名家看后市:长阴破位不必慌
    每日一招:补仓需遵守的技巧
  • 原文地址:https://www.cnblogs.com/13ZY/p/13785733.html
Copyright © 2020-2023  润新知