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;
}
原文地址:https://www.cnblogs.com/13ZY/p/13785733.html