Description
求nn个物品选出至多个的方案数
Input
第一行一整数TT表示用例组数,每组用例输入两个整数
Output
输出结果模109+7109+7
Sample Input
2
5 2
1000 500
Sample Output
16
924129523
Solution
由于∑i=1m+1Cin=∑i=0mCin+Cm+1n∑i=1m+1Cni=∑i=0mCni+Cnm+1,∑i=0mCin+1=2∑i=0mCin−Cmn∑i=0mCn+1i=2∑i=0mCni−Cnm,故每次n,mn,m变化11都可以维护答案,对所有查询莫队即可
Code
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
#define maxn 100005
#define mod 1000000007
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int inv[maxn],fact[maxn],sum[maxn];
void init(int n=1e5)
{
fact[0]=1;
for(int i=1;i<=n;i++)fact[i]=mul(i,fact[i-1]);
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
sum[0]=1;
for(int i=1;i<=n;i++)sum[i]=mul(sum[i-1],inv[i]);
}
int T,unit,ans[maxn];
struct node
{
int l,r,id;
bool operator<(const node &a)const
{
if (l/unit==a.l/unit)return r<a.r;
return l/unit<a.l/unit;
}
}query[maxn];
int C(int n,int m)
{
if(m<0||m>n)return 0;
return mul(fact[n],mul(sum[m],sum[n-m]));
}
int main()
{
init();
scanf("%d",&T);
unit=(int)sqrt((double)T);
for(int i=0;i<T;i++)
{
scanf("%d%d",&query[i].l,&query[i].r);
query[i].id=i;
}
sort(query,query+T);
int l=1,r=0;
int temp=1;
for(int i=0;i<T;i++)
{
while(r<query[i].r)
{
r++;
temp=add(temp,C(l,r));
}
while(r>query[i].r)
{
temp=add(temp,mod-C(l,r));
r--;
}
while(l<query[i].l)
{
temp=add(temp,temp);
temp=add(temp,mod-C(l,r));
l++;
}
while(l>query[i].l)
{
temp=add(temp,C(l-1,r));
temp=mul(temp,inv[2]);
l--;
}
ans[query[i].id]=temp;
}
for(int i=0;i<T;i++)printf("%d\n",ans[i]);
return 0;
}