HDU6333 2018多校第四场(莫队+组合数)

题意

T组样例,给两个数n,m,求下式。

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

题解

先观察一手杨辉三角找找规律

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

可以得到

f(n,m+1)=f(n,m)+C(n,m+1)

f(n+1,m)=2f(n,m)-C(n,m).

抽象的看由(n,m)可以得到(n-1,m)(n+1,m)(n,m-1)(n,m+1)

所以可以用莫队来解决。

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define ll long long

const int maxn =100000+5;
const int mod =1000000007;
ll ans[maxn],fac[maxn]={1,1},inv[maxn]={1,1},f[maxn]={1,1},len;

int T;

ll cal(ll a,ll b) //求组合数
{
    if(b>a)
        return 0;
    return fac[a]*inv[b]%mod*inv[a-b]%mod;
}

void init()
{
    for(int i=2; i<=maxn-1; i++)
    {
        fac[i]=fac[i-1]*i%mod;         //i的阶乘
        f[i]=(mod-mod/i)*f[mod%i]%mod; //i的逆元
        inv[i]=inv[i-1]*f[i]%mod;      //逆元的前缀积
    }
}

struct Query
{
    ll L,R,block;
    int ID;
    Query(){};
    Query(ll l, ll r, int ID) :L(l), R(r), ID(ID){
        block=l/len;
    }
   bool operator<(const Query rhs)const{
        if(block ==rhs.block)
            return R<rhs.R;
        return block <rhs.block;
   }
}queries[maxn];


int main()
{
    len=sqrt(maxn);///块长度
    init();

    scanf("%d",&T);
    for(int i=1; i<=T; i++)
    {
        ll l,r;
        scanf("%lld %lld",&r,&l);
         queries[i]=Query(l,r,i);
    }
    sort(queries+1,queries+T+1);

    int l=0,r=1;
    ll val = 1;
    for(int i=1; i<=T; i++)
    {
      while(r<queries[i].R)
      {
          val=(2ll*val%mod+mod-cal(r++,l))%mod;
      }
      while(r>queries[i].R)
      {
          val=(val+cal(--r,l))%mod*f[2]%mod;
      }

      while(l<queries[i].L)
      {
          val=(val+cal(r,++l))%mod;
      }

      while(l>queries[i].L)
      {
          val=(val+mod-cal(r,l--))%mod;
      }
        ans[queries[i].ID]=val;
    }
    for(int i=1; i<=T; i++)
        printf("%lld\n",ans[i]);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值