杭电多校赛4 HDU - 6333 Harvest of Apples

There are nn apples on a tree, numbered from 11 to nn. 
Count the number of ways to pick at most mm apples. 

Input

The first line of the input contains an integer TT (1≤T≤105)(1≤T≤105) denoting the number of test cases. 
Each test case consists of one line with two integers n,mn,m (1≤m≤n≤105)(1≤m≤n≤105). 

Output

For each test case, print an integer representing the number of ways modulo 109+7109+7.

Sample Input

2
5 2
1000 500

Sample Output

16
924129523

题意:求C(n,0)+.....C(n,m);

思路:预处理+莫队

首先预处理阶乘和阶乘的逆元

定义 S(n, m) = \sum_{i = 0} ^ {m} {n \choose i}S(n,m)=∑ ​i=0 ​m ​​ ( ​i ​n ​​ ),不难发现 S(n, m) = S(n, m - 1) + {n \choose m}, S(n, m) = 2S(n - 1, m) - {n - 1 \choose m}S(n,m)=S(n,m−1)+( ​m ​n ​​ ),S(n,m)=2S(n−1,m)−( ​m ​n−1 ​​ )。也就是说,如果我们知道 S(n, m)S(n,m),就能以 O(1)O(1) 的代价计算出 S(n - 1, m), S(n, m - 1), S(n + 1, m), S(n, m + 1)S(n−1,m),S(n,m−1),S(n+1,m),S(n,m+1),可以采用莫队算法。定义S(n,m)为前m项之和,那么可以推出s(n,m)=2*s(n-1,m)-c(n-1,m)

也就是说,如果我们知道s(n,m),那么s(n+1,m)就可以知道了

所以离线处理,先按m的大小分块,再按n 从小到大排序

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
#include <stack>
typedef long long ll;
using namespace std;
const int maxn=1e5+10;
const int INF=1e9;
const int mod=1e9+7;
const int MOD=1e9+7;
struct query
{
    int n, k, id;
} q[maxn];
bool cmp(query a,query b)
{
    return a.n<b.n;
}
int cnt, mx, chunk;
ll fac[maxn], inv[maxn], res[maxn], in_chunk[maxn];
vector <query> vec[maxn];
ll qpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
        {
            ans=ans*a%mod;
        }
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
int C(int a, int b)
{
    return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
}
void init()
{
    mx = 100000;
    fac[0] = 1;
    for (int i = 1; i <= mx; ++ i) fac[i] = 1ll * fac[i - 1] * i % mod;
    inv[mx] = qpow(fac[mx], MOD - 2); 
    for (int i = mx - 1; ~i; -- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}
int main(int argc, char const *argv[])
{
    init();
    chunk = sqrt(mx);
    cnt = 1;
    for(int i=1;i<=mx;i+=chunk)
    {
        for(int j=i;j<i+chunk&&j<=mx;j++)
        {
            in_chunk[j]=cnt;
        }
        cnt++;
    }
    cnt-=1;
    int T;
    cin>>T;
    for(int i=1;i<=T;i++)
    {
        scanf("%d%d",&q[i].n,&q[i].k);
        q[i].id=i;
        vec[in_chunk[q[i].k]].push_back(q[i]);//按k分块
    }
    for(int i=1;i<=cnt;i++)
    {
        if(vec[i].size())
        {
            sort(vec[i].begin(),vec[i].end(),cmp);
            int ans=0,down=vec[i][0].n,up=-1;
            for(int j=0;j<vec[i].size();j++)
            {
                while(down<vec[i][j].n)
                {
                    ans=(0ll+ans+ans+mod-C(down++,up))%mod;
                }
                while(up<vec[i][j].k)
                {
                    ans=(ans+C(down,++up))%mod;
                }
                while(up>vec[i][j].k)
                {
                    ans=(ans-C(down,up--)+mod)%mod;
                }
                res[vec[i][j].id]=ans;
            }
        }
    }
    for(int i=1;i<=T;i++)
    {
        printf("%d\n",res[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/81347271
今日推荐