mo题

https://vjudge.net/problem/HDU-6333

官方题解:

​ 莫队算法。可以有这样定义
\[ S(n,m)=C_n^0+C_n^1+C_n^2+\cdots+C_n^m \]
然后很明显就能知道这样得关系
\[ S(n,m)=S(n,m-1)+C_n^m \]

\[ S(n,m)=2*S(n-1,m)-C_{n-1}^m \]

这样知道 S(n, m) 可以有O(1)得代价去得到S(n-1, m) S(n+1, m) S(n,m-1) S(n, m+1)

剩下的就是一个莫队板子了。

const ll maxn=1e5+7;
const ll mod=1e9+7;

struct node{
    ll n, m, id;
}Q[maxn];

ll ans[maxn];
ll fac[maxn];  //阶乘
ll ni[maxn];  //逆元
ll N,M,Ans,ni2,sz;  //sz表示根号MAX

ll qm(ll a, ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res%mod;
}

bool cmp(node a, node b){
    if(a.n/sz==b.n/sz) return a.m<b.m;
    return a.n/sz<b.n/sz;
}

void init(){
    fac[0]=1;
    ni2=qm(2, mod-2);
    for(int i=1; i<maxn; i++)
        fac[i]=fac[i-1]*i%mod;  //计算阶乘
    ni[maxn-1]=qm(fac[maxn-1], mod-2);
    for(int i=maxn-2; i>=0; i--)
        ni[i]=ni[i+1]*(i+1)%mod;  //计算逆元
}

ll C(ll n, ll m){
    return fac[n]*ni[n-m]%mod*ni[m]%mod;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    ll t;
    cin>>t;
    sz=sqrt(maxn);
    init();
    for(int i=0; i<t; i++){
        cin>>Q[i].n>>Q[i].m;
        Q[i].id=i;
    }
    sort(Q,Q+t,cmp);
    N=1;M=1;Ans=2;
    for(int i=0;i<t;i++){
        while(N<Q[i].n){
            ++N;
            Ans=(Ans*2%mod+mod-C(N-1, M))%mod;
        }
        while(N>Q[i].n){
            Ans=(Ans+C(N-1, M))%mod*ni2%mod;
            N--;
        }
        while(M<Q[i].m){
            ++M;
            Ans=(Ans+C(N, M))%mod;
        }
        while(M>Q[i].m){
            Ans=(Ans+mod-C(N, M))%mod;
            M--;
        }
        ans[Q[i].id]=Ans;
    }
    for(int i=0;i<t;i++){
        cout<<ans[i]<<endl;
    }
    return 0;
}

还有相关练习题。。
https://vjudge.net/problem/CodeForces-617E
https://vjudge.net/problem/CodeForces-86D
https://vjudge.net/problem/SPOJ-DQUERY
https://vjudge.net/problem/HYSBZ-2038
(待补。。。)

猜你喜欢

转载自www.cnblogs.com/Chirsilver/p/11254249.html
今日推荐