HDU 6333 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): 2203    Accepted Submission(s): 858

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 Iput

2 5 2

1000 500

Sample Output

16

924129523

 

题目:

给出T组n和m(1<=T<=1e5, 1<=m<=n<=1e5)。

\sum_{i=0}^{m}C_{n}^{i}

思路:

首先看测试数据很大,所以求解S(n,m)的时间复杂度绝对小于O(n),如果每个测试用例独立的计算肯定是超时的

所以应该想到离线来计算,用到莫队算法,这时候就要把他想成一个区间了,并且要退出区间左右移动的转移式

S(l,r)=S(l,r+1)-C(l,r+1)     
        =S(l,r-1)+C(l,r);     
        =2*S(l-1,r)-C(l-1,r)  (由杨辉三角得出)
        =(S(l+1,r)+C(l,r))/2; 

 

get1:

ans=((ans+comb(--L,R))/2.0)mod;    ×

ans=((ans+comb(--L,R))*inv[2])%mod;  √

 

#include <cstdio>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <iostream>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N = 1e5+7;        
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 7;

struct node
{
    int l,r,id;
}p[N];

int F[N], Finv[N], inv[N]; 
int unit;
ll res[N];
void init(){
    F[0] = Finv[0] = inv[1] = 1;
    for (register int i = 2; i < N; i++)
        inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod;
    for (register int i = 1; i < N; i++){
        F[i] = F[i - 1] * 1ll * i % mod;
        Finv[i] = Finv[i - 1] * 1ll * inv[i] % mod;
    }
}
int comb(int n, int m){///comb(n, m)¾ÍÊÇC(n, m)
    if (m < 0 || m > n) return 0;
    return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}

bool cmp(node a,node b)
{
    if(a.l/unit!=b.l/unit) return a.l<b.l;
    return a.r<b.r;
}
int main()
{
    int t,i,L,R;
    ll ans;
    init();
    scanf("%d",&t);
    unit=sqrt(maxn);
    for(i=1;i<=t;i++)
    {
        scanf("%d%d",&p[i].l,&p[i].r);
        p[i].id=i;
    }
    sort(p+1,p+1+t,cmp);
    L=1;R=0;
    ans=1;
    for(i=1;i<=t;i++)
    {
        while(L<p[i].l) ans=(2*ans-comb(L++,R)+mod)%mod;
        while(L>p[i].l) ans=((ans+comb(--L,R))*inv[2])%mod;
        while(R<p[i].r) ans=(ans+comb(L,++R))%mod;
        while(R>p[i].r) ans=(ans-comb(L,R--)+mod)%mod;
        res[p[i].id]=ans;
    }
    for(i=1;i<=t;i++) printf("%I64d\n",res[i]);
    return 0;
}
/*
S(l,r)=S(l,r+1)-C(l,r+1)    ->S(l,r+1)=S(l,r)+C(l,r+1)
      =S(l,r-1)+C(l,r);     ->S(l,r-1)=S(l,r)-C(l,r)
      =2*S(l-1,r)-C(l-1,r)  ->S(l-1,r)=(S(l,r)+C(l-1,r))/2
      =(S(l+1,r)+C(l,r))/2; ->S(l+1,r)=2*S(l,r)-C(l,r)
*/






 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值