hdu6333 Problem B. 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): 2643 Accepted Submission(s): 1028

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≤m≤n≤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;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int MAX = 1e5 + 5;
const int block = (int)sqrt(1e5);
const LL mod = 1e9 + 7;
LL fac[MAX],inv[MAX];
typedef struct Node
{
    int n,m,id,block;
    long long ans;
}Node;
Node node[MAX];
//按块排序,块内按r排序
bool cmp1(const Node &b,const Node &c)
{
    if(b.block == c.block){
        return b.m < c.m;
    }
    else{
        return b.block < c.block;
    }
}

bool cmp2(const Node &b,const Node &c)
{
    return b.id < c.id;
}

LL quick_mod(LL n,LL m)
{
    LL sum = 1;
    LL x = n;
    while(m)
    {
        if(m & 1)
            sum= (sum * x) % mod;
        m >>= 1;
        x = (x * x) % mod;
    }
    return sum;
}

void init()
{
    fac[0]=1;inv[0]=1;
    for(int i = 1;i < MAX;i++)
    {
    //求阶乘
        fac[i] = (fac[i-1] * i) % mod;
    //求阶乘的逆元
        inv[i] = quick_mod(fac[i], mod -  2) % mod;
    }
}

int main()
{
    int t;
    init();
    scanf("%d",&t);
    for(int i = 0;i < t;++i)
    {
        scanf("%d %d",&node[i].n,&node[i].m);
        node[i].id = i;
        node[i].block = node[i].n / block;
    }
    sort(node,node + t,cmp1);
    LL sum = 1;
    for(int i = 1,k = node[0].n;i <= node[0].m;++i)
    {
        sum = (sum + fac[k] * inv[i] % mod * inv[k - i] % mod) % mod;
    }
    node[0].ans = sum;
    int l = node[0].n,r = node[0].m;
    int L,R;
    for(int i = 1;i < t;++i)
    {
        L = node[i].n;
        R = node[i].m;
        while(L > l){
            sum = (2 * sum - fac[l] * inv[r] % mod * inv[l - r] % mod + mod) % mod;
            l++;
        }
        while(L < l){
            sum = (sum + fac[l - 1] * inv[r] % mod * inv[l -  1 - r] % mod) % mod * inv[2] % mod;
            l--;
        }
        while(R > r){
            sum = (sum + fac[l] * inv[r + 1] % mod * inv[l - r - 1] % mod) % mod;
            r++;
        }
        while(R < r)
        {
            sum = (sum - fac[l] * inv[r] % mod * inv[l - r] % mod + mod) % mod;
            r--;
        }
        node[i].ans = sum;
    }
    sort(node,node + t,cmp2);
    for(int i = 0;i < t;++i)
    {
        printf("%lld\n",node[i].ans);
    }
    return 0;
}

莫对算法讲解:http://www.mamicode.com/info-detail-2240755.html
https://blog.csdn.net/thinfatty/article/details/72581276
https://www.cnblogs.com/CsOH/p/5904430.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值