链接: https://vjudge.net/contest/304434#problem/B
题意: 一颗树上有n颗苹果,求取不多于m个苹果有多少种拿法
思路: 莫队加组合数
在左右转移时要注意组合数
C
n
m
C_{n}^{m}
Cnmm必须大于等于n,所以m先降,再降n,或者n先升再升m,因为少考虑了这一点,wa了好多发,哭唧唧
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll ans[N],ret=1;
int block;
ll inv[N],fac[N];
struct node
{
int n,m;
int id;
}a[N];
bool cmp(node x,node y)
{
if(x.n/block==y.n/block)
return x.m<y.m;
return x.n<y.n;
}
ll quick_fast(ll x,ll n)
{
ll ans=1;
while(n)
{
if(n&1)
{
ans=ans*x%mod;
}
x=x*x%mod;
n>>=1;
}
return ans;
}
void init()
{
block=sqrt(N);
fac[0]=1;
for(int i=1;i<N;i++)
{
fac[i]=fac[i-1]*i%mod;
}
inv[N-1]=quick_fast(fac[N-1],mod-2);
for(int i=N-2;i>=0;i--)
{
inv[i]=(inv[i+1]*(i+1))%mod;
}
}
ll C(int n,int m)
{
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
init();
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
scanf("%d%d",&a[i].n,&a[i].m);
a[i].id=i;
}
sort(a+1,a+1+T,cmp);
int n=1,m=0;
for(int i=1;i<=T;i++)
{
while(m>a[i].m)
{
ret=(ret-C(n,m)+mod)%mod;
m--;
}
while(n>a[i].n)
{
ret=(ret+C(n-1,m))*inv[2]%mod;
n--;
}
while(n<a[i].n)
{
ret=(ret*2-C(n,m)+mod)%mod;
n++;
}
while(m<a[i].m)
{
ret=(ret+C(n,m+1))%mod;
m++;
}
ans[a[i].id]=ret;
}
for(int i=1;i<=T;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}