sum「莫队」

在格尔巴乔夫新思维带领下数学题也可以用莫队了

觉得思路很棒,主要是莫队思想在数学题上应用

题目让求的是$\sum\limits_{i=0}^{i<=m} C_{n}^{m}$十万组询问,$n,m$范围十万

设$S_{n}^{m}=\sum\limits_{i=0}^{i<=m} C_{n}^{m}$,

根据定义$S_{n}^{m}=S_{n}^{m-1}+C_{n}^{m}$

又因为$C_{n}^{m}+C_{n}^{m-1}=C_{n+1}^{m}$

把上面柿子展开得到$S_{n}^{m}=2*S{n-1}^{m}-C(n-1,m)$

于是就可以愉快的莫队了

$S_{l}^{r}=2*S_{l}^{r-1}-C_{r-1}^{l}$

$S_{l}^{r}=S_{l-1}^{r}+C_{r,l}$

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 1111111
const ll mod=1e9+7;
ll id,q,n,m,l=1,r=0;
ll ans=1,t;
ll jie[A],ni[A],realans[A],belong[A];
struct node{
    ll l,r,id;
    friend bool operator < (const node &a,const node &b){
        return belong[a.l]==belong[b.l]?a.r<b.r:a.l<b.l;
    }
}mo[A];
ll meng(ll x,ll k){
    ll ans=1;
    for(;k;k>>=1,x=x*x%mod)
        if(k&1)
            ans=ans*x%mod;
    return ans;
}
ll C(ll x,ll y){
    return jie[x]*ni[y]%mod*ni[x-y]%mod;
}
//s_n,m=2*s_n-1,m-C(n-1,m)
//s_r,l=2*s_r-1,l-C(r-1,l)
//s_r,l=s_r,l-1+C(r,l)
//S_l,r=2*S_l,r-1-C(r-1,l)
//S_l,r=S_l-1,r+C(r,l)
int main(){
    scanf("%lld",&id);
    scanf("%lld",&q);
    jie[0]=ni[0]=1;
    t=sqrt(100000);
    for(ll i=1;i<=100100;i++)
        jie[i]=jie[i-1]*i%mod,belong[i]=(i-1)/t+1;
    ni[100100]=meng(jie[100100],mod-2);
    for(ll i=100099;i>=1;i--)
        ni[i]=ni[i+1]*(i+1)%mod;
    for(ll i=1;i<=q;i++){
        scanf("%lld%lld",&mo[i].r,&mo[i].l);
        mo[i].id=i;
    }
    sort(mo+1,mo+q+1);
    for(ll i=1;i<=q;i++){
        while(l<mo[i].l) l++,ans=(ans+C(r,l))%mod;
        while(l>mo[i].l) ans=(ans-C(r,l)+mod)%mod,l--;
        while(r<mo[i].r) r++,ans=(2*ans-C(r-1,l)+mod)%mod;
        while(r>mo[i].r) ans=(((ans+C(r-1,l)))*meng(2,mod-2))%mod,r--;
//        printf("n=%lld m=%lld ans=%lld\n",mo[i].r,mo[i].l,ans);
        realans[mo[i].id]=ans;
    }
    for(ll i=1;i<=q;i++){
        printf("%lld\n",realans[i]);
    }
}
View Code

 

posted @ 2019-10-09 19:39  znsbc  阅读(159)  评论(1编辑  收藏  举报