HDU 6333 Harvest of Apples 【莫队】【逆元线性筛】

Problem B. Harvest of Apples

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2017    Accepted Submission(s): 784


 

Problem Description

There are n apples on a tree, numbered from 1 to n.
Count the number of ways to pick at most m apples.

 

 

Input

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

 

 

Output

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

 

 

Sample Input

 

2 5 2 1000 500

 

 

Sample Output

 

16 924129523

预处理逆元参考文章:链接

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int Mod = 1e9 + 7;
const int MAX = 1e5 + 7;
int sz;
struct node{
    int l, r, id;
    bool operator < (const node &a) const{
        if(l / sz == a.l / sz) return r < a.r;
        return l < a.l;
    }
} a[MAX];
ll res[MAX], ans = 1;
ll fac[MAX], inv[MAX];
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;
}
void init(){
    fac[1] = fac[0] = 1;
    for(int i = 2; i <= MAX; i++) fac[i] = fac[i - 1] * i % Mod;
    inv[MAX] = qpow(fac[MAX], Mod - 2);
    for(int i = MAX - 1; i >= 0; i--)
        inv[i] = (inv[i + 1] * (i + 1)) % Mod;
}
ll cnm(ll x, ll y){
    return fac[x] * inv[y] % Mod * inv[x - y] % Mod;
}
void del(int l, int r, int flag){
    if(flag)
        ans = (ans * 2 % Mod - cnm(l, r) + Mod) % Mod;
    else
        ans = (ans - cnm(l, r) + Mod) % Mod;
}
void add(int l, int r, int flag){
    if(flag)
        ans = (ans + cnm(l, r)) % Mod * inv[2] % Mod;
    else
        ans = (ans + cnm(l, r)) % Mod;
}
int main(){
    int n;
    init();
    scanf("%d", &n);
    sz = sqrt(n);
    for(int i = 1; i <= n; i++){
        scanf("%d%d", &a[i].l, &a[i].r);
        a[i].id = i;
    }
    sort(a + 1, a + 1 + n);
    int p = 1, q = 0;
    for(int i = 1; i <= n; i++){
        int L = a[i].l;
        int R = a[i].r;
        while(p < L){
            del(p, q, 1);
            p++;
        }
        while(p > L){
            add(p - 1, q, 1);
            p--;
        }
        while(q < R){
            q++;
            add(p, q, 0);
        }
        while(q > R){
            del(p, q, 0);
            q--;
        }
        res[a[i].id] = ans;
    }
    for(int i = 1; i <= n; i++) printf("%lld\n", res[i]);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值